InfraRunBook
    Back to articles

    How to Configure DNSSEC on BIND9 (Ubuntu) – Complete Step-by-Step Guide

    DNS
    Published: Feb 15, 2026
    Updated: Feb 15, 2026

    Learn how to configure DNSSEC on BIND9 running on Ubuntu to cryptographically sign your DNS zones, protect against cache poisoning, and validate DNS responses end-to-end.

    How to Configure DNSSEC on BIND9 (Ubuntu) – Complete Step-by-Step Guide

    Introduction to DNSSEC

    DNSSEC (Domain Name System Security Extensions) adds a layer of cryptographic authentication to DNS responses. Without DNSSEC, an attacker can forge DNS replies (cache poisoning, man-in-the-middle) and redirect users to malicious hosts. DNSSEC solves this by digitally signing every DNS record set in a zone so that resolvers can verify the authenticity and integrity of the data they receive.

    This guide walks you through the entire process of enabling DNSSEC on an authoritative BIND9 server running on Ubuntu 22.04 or 24.04. We will cover key generation, zone signing, DS record submission, DNSSEC validation on resolvers, key rollover strategy, and automated re-signing with

    inline-signing
    .


    Prerequisites

    • Ubuntu 22.04 LTS or 24.04 LTS server with root or sudo access
    • BIND9 installed and serving at least one authoritative zone (see our guide: How to Install BIND9 on Ubuntu)
    • Access to your domain registrar's control panel (to submit DS records)
    • NTP synchronised clock (
      timedatectl status
      should show System clock synchronized: yes)

    Step 1 — Verify Your Current BIND9 Installation

    Before configuring DNSSEC, confirm BIND is running and your zone is resolving properly.

    sudo systemctl status named
    dig @localhost example.com SOA +short

    You should see an active service and a valid SOA record. Also verify the BIND version supports DNSSEC features:

    named -V | grep -i dnssec

    Look for

    --with-dnssec
    or DNSSEC-related libraries in the output. All modern Ubuntu packages of BIND9 (9.18+) include full DNSSEC support.


    Step 2 — Understand DNSSEC Key Types

    DNSSEC uses two types of keys:

    • ZSK (Zone Signing Key): Signs the individual record sets (RRsets) in your zone. Rotated more frequently (every 1–3 months).
    • KSK (Key Signing Key): Signs the DNSKEY RRset itself. Its hash is published as a DS record in the parent zone. Rotated less frequently (every 1–2 years).

    We will use the ECDSAP256SHA256 algorithm (algorithm 13), which is the current best practice recommended by NIST and the IETF (RFC 8624). It provides strong security with small key and signature sizes.


    Step 3 — Create a Key Directory

    sudo mkdir -p /etc/bind/keys/example.com
    sudo chown bind:bind /etc/bind/keys/example.com
    sudo chmod 750 /etc/bind/keys/example.com

    Keeping keys in a dedicated directory with restricted permissions is a security best practice.


    Step 4 — Generate the KSK and ZSK

    4a — Generate the KSK

    cd /etc/bind/keys/example.com
    sudo dnssec-keygen -a ECDSAP256SHA256 -n ZONE -f KSK example.com

    This produces two files, for example:

    Kexample.com.+013+12345.key    (public)
    Kexample.com.+013+12345.private (private)

    4b — Generate the ZSK

    sudo dnssec-keygen -a ECDSAP256SHA256 -n ZONE example.com

    This produces another key pair, for example:

    Kexample.com.+013+67890.key
    Kexample.com.+013+67890.private

    4c — Set correct ownership

    sudo chown bind:bind /etc/bind/keys/example.com/*
    sudo chmod 640 /etc/bind/keys/example.com/*.private
    sudo chmod 644 /etc/bind/keys/example.com/*.key

    Step 5 — Include the Keys in Your Zone File

    Open your zone file (e.g.,

    /etc/bind/zones/db.example.com
    ) and add
    $INCLUDE
    directives at the bottom:

    ; /etc/bind/zones/db.example.com
    $TTL 86400
    @   IN  SOA ns1.example.com. admin.example.com. (
                2026021501  ; Serial
                3600        ; Refresh
                1800        ; Retry
                1209600     ; Expire
                86400 )     ; Negative Cache TTL
    
    @       IN  NS  ns1.example.com.
    @       IN  NS  ns2.example.com.
    
    ns1     IN  A   203.0.113.10
    ns2     IN  A   203.0.113.11
    @       IN  A   203.0.113.50
    www     IN  CNAME   @
    mail    IN  A   203.0.113.60
    @       IN  MX  10 mail.example.com.
    
    $INCLUDE /etc/bind/keys/example.com/Kexample.com.+013+12345.key
    $INCLUDE /etc/bind/keys/example.com/Kexample.com.+013+67890.key

    Important: Replace the key file names with the actual file names generated in Step 4. Increment the serial number every time you edit the zone.


    Step 6 — Sign the Zone (Manual Method)

    For learning and one-time setups, you can sign the zone manually:

    cd /etc/bind/zones
    sudo dnssec-signzone \
      -A \
      -3 $(head -c 1000 /dev/urandom | sha1sum | cut -b 1-16) \
      -N INCREMENT \
      -o example.com \
      -t \
      -K /etc/bind/keys/example.com \
      db.example.com

    Flags explained:

    • -A
      — generate NSEC3 records for all sets
    • -3 <salt>
      — use NSEC3 with a random salt (mitigates zone enumeration)
    • -N INCREMENT
      — automatically increment the SOA serial
    • -o example.com
      — origin zone name
    • -t
      — print signing statistics
    • -K
      — directory containing the keys

    The command produces

    db.example.com.signed
    and a
    dsset-example.com.
    file containing the DS records.


    Step 7 — Update named.conf to Use the Signed Zone

    Edit your zone declaration in

    /etc/bind/named.conf.local
    :

    zone "example.com" {
        type master;
        file "/etc/bind/zones/db.example.com.signed";
        allow-transfer { 203.0.113.11; };
    };

    Validate the configuration and reload:

    sudo named-checkconf
    sudo named-checkzone example.com /etc/bind/zones/db.example.com.signed
    sudo rndc reload example.com

    Step 8 — Configure Automatic Inline Signing (Recommended for Production)

    Manual signing is error-prone. BIND9 supports inline-signing, which automatically signs the zone and manages re-signing before signatures expire.

    zone "example.com" {
        type master;
        file "/etc/bind/zones/db.example.com";
        key-directory "/etc/bind/keys/example.com";
        inline-signing yes;
        auto-dnssec maintain;
        allow-transfer { 203.0.113.11; };
    };

    Note on BIND 9.18+: The

    auto-dnssec
    directive is deprecated in favour of
    dnssec-policy
    . Here is the modern approach:

    // In /etc/bind/named.conf.options or named.conf.local
    dnssec-policy "standard" {
        keys {
            ksk key-directory lifetime unlimited algorithm ecdsap256sha256;
            zsk key-directory lifetime 90d algorithm ecdsap256sha256;
        };
        nsec3param iterations 0 optout no salt-length 0;
        max-zone-ttl 86400;
        zone-propagation-delay 300;
        parent-ds-ttl 3600;
        parent-propagation-delay 7200;
    };
    
    zone "example.com" {
        type master;
        file "/etc/bind/zones/db.example.com";
        key-directory "/etc/bind/keys/example.com";
        dnssec-policy "standard";
        inline-signing yes;
        allow-transfer { 203.0.113.11; };
    };

    With

    dnssec-policy
    , BIND automatically generates keys, signs the zone, re-signs before expiration, and handles ZSK rollovers on the defined schedule.

    sudo named-checkconf
    sudo systemctl restart named
    sudo rndc signing -list example.com

    Step 9 — Extract and Submit the DS Record to Your Registrar

    The DS (Delegation Signer) record links your signed zone to the parent zone (e.g.,

    .com
    ). Extract it from the KSK:

    sudo dnssec-dsfromkey /etc/bind/keys/example.com/Kexample.com.+013+12345.key

    Output example:

    example.com. IN DS 12345 13 2 E2D3C916F6DEEAC73294E8268FB5885044A833FC5459588F4A9184CFC41A5766

    The fields are: Key Tag, Algorithm, Digest Type (2 = SHA-256), and Digest. Log in to your registrar and add this DS record. Most registrars have a dedicated "DNSSEC" or "DS Records" section.

    Tip: Always submit the SHA-256 digest (type 2). SHA-1 (type 1) is deprecated.


    Step 10 — Verify DNSSEC Is Working

    10a — Local verification with dig

    dig @localhost example.com A +dnssec +short

    You should see the A record followed by an RRSIG record. The

    ad
    (Authenticated Data) flag in the header confirms validation:

    dig @localhost example.com A +dnssec | grep flags
    ;; flags: qr aa rd; QUERY: 1, ANSWER: 2, AUTHORITY: 0, ADDITIONAL: 1

    10b — Test from an external validating resolver

    dig @8.8.8.8 example.com A +dnssec +multi

    Look for the

    ad
    flag in the response. If present, Google's resolver validated your DNSSEC chain successfully.

    10c — Online tools

    • DNSViz:
      https://dnsviz.net/d/example.com/dnssec/
    • Verisign DNSSEC Analyzer:
      https://dnssec-analyzer.verisignlabs.com/example.com
    • ICANN DNSSEC check:
      https://dnssec-debugger.verisignlabs.com/

    Step 11 — Enable DNSSEC Validation on Your Recursive Resolver

    If your BIND9 server also acts as a recursive resolver for clients, enable validation in

    /etc/bind/named.conf.options
    :

    options {
        directory "/var/cache/bind";
        recursion yes;
        allow-recursion { 10.0.0.0/8; 172.16.0.0/12; 192.168.0.0/16; };
        dnssec-validation auto;
        listen-on { 127.0.0.1; 10.0.0.1; };
    };

    dnssec-validation auto;
    tells BIND to use the built-in root trust anchors (managed via
    managed-keys
    or
    trust-anchors
    statements that ship with the package). Reload:

    sudo rndc reconfig
    sudo rndc validation-status

    Test validation is working by querying a known DNSSEC-signed domain:

    dig @127.0.0.1 isc.org A +dnssec
    # Should return ad flag

    Test a domain with a deliberately broken signature:

    dig @127.0.0.1 dnssec-failed.org A
    # Should return SERVFAIL

    Step 12 — Key Rollover Strategy

    Keys must be rotated periodically. Here is a practical rollover plan:

    ZSK Rollover (Pre-Publish Method)

    1. Pre-publish: Generate new ZSK and add it to the zone (both old and new ZSK are published).
    2. Wait for the old DNSKEY TTL to expire (so all caches have the new key).
    3. Activate: Sign the zone with the new ZSK.
    4. Wait for the old RRSIG TTL to expire.
    5. Remove: Delete the old ZSK from the zone.

    With

    dnssec-policy
    , this is fully automated based on the
    lifetime
    you configured (e.g.,
    90d
    ).

    KSK Rollover (Double-DS Method)

    1. Generate a new KSK and add it to the zone.
    2. Compute the new DS record and submit it to your registrar alongside the old DS.
    3. Wait for the parent zone TTL to expire.
    4. Remove the old KSK from your zone.
    5. Remove the old DS record from the registrar.

    Monitor the rollover with:

    sudo rndc signing -list example.com
    sudo rndc dnssec -status example.com   # BIND 9.18+

    Step 13 — Monitoring and Alerting

    Set up monitoring to catch signature expiration or validation failures:

    # Check RRSIG expiry with a script
    RRSIG_EXPIRY=$(dig @localhost example.com RRSIG +short | head -1 | awk '{print $5}')
    EXPIRY_EPOCH=$(date -d "$RRSIG_EXPIRY" +%s 2>/dev/null || date -j -f "%Y%m%d%H%M%S" "$RRSIG_EXPIRY" +%s)
    NOW_EPOCH=$(date +%s)
    DAYS_LEFT=$(( (EXPIRY_EPOCH - NOW_EPOCH) / 86400 ))
    
    if [ "$DAYS_LEFT" -lt 7 ]; then
        echo "WARNING: RRSIG for example.com expires in $DAYS_LEFT days" | mail -s "DNSSEC Alert" admin@example.com
    fi

    Add this to a cron job running daily:

    sudo crontab -e
    # Add:
    0 6 * * * /usr/local/bin/check-dnssec-expiry.sh

    Step 14 — Troubleshooting Common DNSSEC Issues

    Problem: SERVFAIL responses after enabling DNSSEC

    • Check that the DS record at the registrar matches your KSK exactly.
    • Verify system clock is synchronised:
      timedatectl status
    • Check signatures have not expired:
      dig @localhost example.com RRSIG
    • Review BIND logs:
      sudo journalctl -u named -f

    Problem: "no valid RRSIG" in logs

    • Re-sign the zone or verify
      inline-signing yes;
      is active.
    • Ensure key files have correct ownership (
      bind:bind
      ) and permissions.

    Problem: Parent zone does not have DS record

    • DNSSEC will not validate until the DS is in the parent. Use
      dig example.com DS
      to check.
    • Some registrars take 24–48 hours to propagate DS records.

    Useful debugging commands

    # Check the full chain of trust
    delv @127.0.0.1 example.com A +rtrace
    
    # Verify zone file syntax
    sudo named-checkzone -i full example.com /etc/bind/zones/db.example.com.signed
    
    # Flush resolver cache to test fresh
    sudo rndc flush

    Complete Configuration Summary

    Here is the final

    /etc/bind/named.conf.local
    using the modern
    dnssec-policy
    approach:

    dnssec-policy "standard" {
        keys {
            ksk key-directory lifetime unlimited algorithm ecdsap256sha256;
            zsk key-directory lifetime 90d algorithm ecdsap256sha256;
        };
        nsec3param iterations 0 optout no salt-length 0;
        max-zone-ttl 86400;
        zone-propagation-delay 300;
        parent-ds-ttl 3600;
        parent-propagation-delay 7200;
    };
    
    zone "example.com" {
        type master;
        file "/etc/bind/zones/db.example.com";
        key-directory "/etc/bind/keys/example.com";
        dnssec-policy "standard";
        inline-signing yes;
        allow-transfer { 203.0.113.11; };
        also-notify { 203.0.113.11; };
    };

    And

    /etc/bind/named.conf.options
    for a combined authoritative + recursive setup:

    options {
        directory "/var/cache/bind";
        recursion yes;
        allow-recursion { 10.0.0.0/8; 172.16.0.0/12; 192.168.0.0/16; localhost; };
        dnssec-validation auto;
        listen-on { any; };
        listen-on-v6 { any; };
        allow-query { any; };
        forwarders { };
        auth-nxdomain no;
    };

    Security Best Practices for DNSSEC

    • Use ECDSAP256SHA256 (algorithm 13) — smaller keys, faster verification, widely supported.
    • Use NSEC3 with zero iterations and no salt — RFC 9276 recommends this for optimal performance and compatibility.
    • Protect private keys — restrict permissions to
      bind:bind
      with mode 640.
    • Monitor signature expiry — expired RRSIG records cause total zone failure for validating resolvers.
    • Keep system time accurate — DNSSEC signatures have inception and expiration timestamps.
    • Test before going live — use
      delv
      , DNSViz, and Verisign analyzers before submitting the DS to the parent.
    • Have a rollback plan — know how to remove the DS record from the registrar to disable DNSSEC quickly if needed.
    • Backup your keys — store encrypted key backups off-server. Losing a KSK without the corresponding DS removal causes a broken chain.

    Frequently Asked Questions (FAQ)

    Q1: What is DNSSEC and why do I need it?

    DNSSEC adds cryptographic signatures to DNS records, allowing resolvers to verify that DNS responses have not been tampered with. It protects against cache poisoning, DNS spoofing, and man-in-the-middle attacks on DNS queries.

    Q2: Does DNSSEC encrypt DNS traffic?

    No. DNSSEC provides authentication and integrity but not confidentiality. DNS queries and responses remain in plaintext. For encryption, you need DNS-over-TLS (DoT) or DNS-over-HTTPS (DoH) in addition to DNSSEC.

    Q3: What happens if my DNSSEC signatures expire?

    Validating resolvers will return SERVFAIL for all queries to your zone. Your domain will effectively go offline for users behind validating resolvers (including Google Public DNS, Cloudflare 1.1.1.1, and most ISP resolvers). This is why automated re-signing with

    inline-signing
    or
    dnssec-policy
    is critical.

    Q4: Which DNSSEC algorithm should I use?

    Use ECDSAP256SHA256 (algorithm 13). It is recommended by RFC 8624, produces small signatures (64 bytes vs 256 bytes for RSA-2048), and is supported by all modern resolvers. Avoid RSA-SHA1 (algorithm 5) and DSA (algorithm 3) as they are deprecated.

    Q5: What is the difference between NSEC and NSEC3?

    NSEC proves that a DNS name does not exist by listing the next existing name, which allows zone enumeration (walking the entire zone). NSEC3 hashes the names, making enumeration significantly harder. Use NSEC3 with zero iterations and no salt per RFC 9276.

    Q6: How often should I rotate DNSSEC keys?

    ZSK: every 1–3 months. KSK: every 1–2 years, or when algorithm changes are needed. With BIND9's

    dnssec-policy
    , ZSK rollovers are fully automated. KSK rollovers require DS record updates at the registrar.

    Q7: Can I use DNSSEC with dynamic DNS updates?

    Yes. When using

    inline-signing yes;
    , BIND maintains a separate signed version of the zone. Dynamic updates modify the unsigned zone, and BIND automatically re-signs the affected records.

    Q8: How do I disable DNSSEC if something goes wrong?

    First, remove the DS record from your registrar and wait for the parent zone TTL to expire (typically 24–48 hours). Then remove the

    dnssec-policy
    or
    auto-dnssec
    directives from your BIND configuration, reload BIND, and serve the unsigned zone file.

    Q9: Does DNSSEC work with secondary (slave) name servers?

    Yes. The primary server signs the zone and transfers the signed zone (including RRSIG, DNSKEY, and NSEC/NSEC3 records) to secondaries via AXFR/IXFR. Secondary servers do not need access to the private keys.

    Q10: How do I verify the full DNSSEC chain of trust from root to my domain?

    Use the

    delv
    command (DNSSEC-aware replacement for dig):
    delv @8.8.8.8 example.com A +rtrace
    . For visual chain analysis, use DNSViz at
    https://dnsviz.net/
    . Both tools trace the chain from the root zone through TLD to your domain and report any broken links.

    Frequently Asked Questions

    What is DNSSEC and why do I need it?

    DNSSEC adds cryptographic signatures to DNS records, allowing resolvers to verify that DNS responses have not been tampered with. It protects against cache poisoning, DNS spoofing, and man-in-the-middle attacks on DNS queries.

    Does DNSSEC encrypt DNS traffic?

    No. DNSSEC provides authentication and integrity but not confidentiality. DNS queries and responses remain in plaintext. For encryption, you need DNS-over-TLS (DoT) or DNS-over-HTTPS (DoH) in addition to DNSSEC.

    What happens if my DNSSEC signatures expire?

    Validating resolvers will return SERVFAIL for all queries to your zone. Your domain will effectively go offline for users behind validating resolvers. This is why automated re-signing with inline-signing or dnssec-policy is critical.

    Which DNSSEC algorithm should I use?

    Use ECDSAP256SHA256 (algorithm 13). It is recommended by RFC 8624, produces small signatures, and is supported by all modern resolvers. Avoid RSA-SHA1 and DSA as they are deprecated.

    What is the difference between NSEC and NSEC3?

    NSEC proves that a DNS name does not exist by listing the next existing name, which allows zone enumeration. NSEC3 hashes the names, making enumeration significantly harder. Use NSEC3 with zero iterations and no salt per RFC 9276.

    How often should I rotate DNSSEC keys?

    ZSK: every 1-3 months. KSK: every 1-2 years. With BIND9's dnssec-policy, ZSK rollovers are fully automated. KSK rollovers require DS record updates at the registrar.

    Can I use DNSSEC with dynamic DNS updates?

    Yes. When using inline-signing, BIND maintains a separate signed version of the zone. Dynamic updates modify the unsigned zone, and BIND automatically re-signs the affected records.

    How do I disable DNSSEC if something goes wrong?

    First, remove the DS record from your registrar and wait for the parent zone TTL to expire (typically 24-48 hours). Then remove the dnssec-policy or auto-dnssec directives from your BIND configuration, reload BIND, and serve the unsigned zone file.

    Does DNSSEC work with secondary (slave) name servers?

    Yes. The primary server signs the zone and transfers the signed zone (including RRSIG, DNSKEY, and NSEC/NSEC3 records) to secondaries via AXFR/IXFR. Secondary servers do not need access to the private keys.

    How do I verify the full DNSSEC chain of trust from root to my domain?

    Use the delv command: delv @8.8.8.8 example.com A +rtrace. For visual chain analysis, use DNSViz at https://dnsviz.net/. Both tools trace the chain from the root zone through TLD to your domain and report any broken links.

    Related Articles