Why a signed zone stops being valid on its own
What actually happens after the move to BIND
Reading RRSIG expiration with dig
+cd flag (checking disabled) tells the resolver to skip DNSSEC validation. If the normal query returns SERVFAIL and the +cd query returns the right answer, the problem is DNSSEC, not your records. The third command asks your own authoritative server for the SOA record with DNSSEC data included, so you can see the signatures it is actually serving.
BASH
# Validating resolver: SERVFAIL here points at a validation problem
dig example.com A @8.8.8.8
# Same query with validation disabled: an answer here confirms it is DNSSEC
dig example.com A @8.8.8.8 +cd
# Ask your authoritative server directly and show the signatures it serves
dig example.com SOA @ns1.example.com +dnssec +noall +answerYYYYMMDDHHMMSS format and always in UTC. An illustrative line would begin like example.com. 3600 IN RRSIG SOA 13 2 3600 20261101000000 20261018000000 12345 example.com. .... Here the expiration is the first timestamp, and in this illustrative example it is 1 November.
If the expiration date is in the past, you have found the problem. If it is a few days away and nothing on your server is configured to sign, you have found it early.
Check more than one record type. The SOA and the DNSKEY set are good indicators, but they can be signed with different keys and on different schedules. Check every authoritative nameserver too, not only the primary. A secondary that stopped receiving transfers can keep serving stale signatures after the primary is fixed.
The production pattern: decide who signs before you move
dnssec-policy, which generates keys, signs the zone, and re-signs automatically before signatures expire. The older auto-dnssec option was deprecated in favor of it. A minimal zone definition looks like this. Whether inline-signing must be stated explicitly depends on your BIND version, so check the documentation for the release you run.
TEXT
zone 'example.com' {
type primary;
file '/var/named/example.com.db';
// Generate keys, sign, and keep re-signing using BIND's built-in policy
dnssec-policy default;
// Keep the unsigned file untouched; BIND maintains a signed copy
inline-signing yes;
};named.conf uses double quotes around names and paths. They are shown as single quotes here only for display, so use double quotes in your real config. The zone file should contain only your normal records. Strip out the imported RRSIG, DNSKEY, NSEC, and NSEC3 records so BIND is not serving someone else's signatures next to its own.
There is a catch. BIND's new keys do not match the DS record currently at the registrar, which still points to the old provider's key. Until the DS is updated to match the new key, validators see a broken chain of trust and return SERVFAIL anyway. A mismatched DS after a provider change is its own well-known failure, covered in Kenapa Domain SERVFAIL Setelah Pindah DNS Provider yang Pakai DNSSEC. Doing this without any gap requires either a multi-signer setup where both providers publish each other's keys, or the second option below.
The second option is to go unsigned for the move. Remove the DS record at the registrar first. Wait at least the DS record's TTL, plus some margin, so resolvers forget it. Then move the nameservers to BIND with a plain, unsigned zone. Once the zone is stable on BIND, enable dnssec-policy, let it sign, and publish the new DS. The domain is unprotected by DNSSEC for a short period, but it never goes dark. For many smaller setups this is the more predictable path.
On a BIND server that is signing, rndc dnssec -status example.com shows the policy and key states in recent versions. That confirms BIND believes it is signing. It does not prove resolvers accept the result, so the external check below still matters.
A routine check that catches expiring signatures
BASH
#!/usr/bin/env bash
# Warn when RRSIGs served by an authoritative server are close to expiry.
# Usage: ./rrsig-check.sh example.com ns1.example.com 5
# Requires GNU date (the -d option).
zone="1"; ns="2"; warn_days="${3:-5}"
now=$(date -u +%s)
status=0
for type in SOA DNSKEY; do
# Field 9 of an RRSIG answer line is the expiration time (YYYYMMDDHHMMSS, UTC)
exps=(dig @"ns" "zone" "type" +dnssec +noall +answer | awk '4 == "RRSIG" {print9}')
if [ -z "$exps" ]; then
echo "CRITICAL: no RRSIG for zonetype on $ns"
status=2
continue
fi
for exp in $exps; do
exp_s=(date -u -d "{exp:0:8} {exp:8:2}:{exp:10:2}:${exp:12:2}" +%s)
days=$(( (exp_s - now) / 86400 ))
if [ "days" -lt "warn_days" ]; then
echo "WARNING: zonetype RRSIG expires in days day(s) (exp UTC)"
[ "$status" -eq 0 ] && status=1
fi
done
done
exit $statusdig example.com @8.8.8.8 status check. The script catches problems days in advance, and the resolver check confirms what real users see.
If a domain also receives mail, an expired signature affects more than the website. Sending servers that validate DNSSEC defer or bounce mail just as browsers fail to resolve the site. That pattern is described in Why Inbound Mail Bounces After a DNSSEC Key Rollover Even With a Healthy Server.
The practical takeaway is simple. When a signed zone moves, the signing job has to move with it, or be shut down cleanly by removing the DS first. Before any cutover, look at the RRSIG expiration dates, decide who signs afterwards, and set up a daily check that reads those dates from your own nameservers. Then the expiry date becomes a calendar item instead of an outage.