- Shell 53%
- Python 25.6%
- Jinja 14.8%
- Dockerfile 6.6%
|
|
||
|---|---|---|
| .github/workflows | ||
| container | ||
| test | ||
| README.md | ||
RFC 2136 DNS Container
A containerized authoritative DNS server with support for dynamic DNS updates using RFC 2136.
Useful for:
- Dynamic DNS: Update DNS records for hosts with changing IP addresses, such as home internet connections.
- ACME DNS-01 challenges: Allow ACME clients to create and remove TXT records for certificate validation.
The container runs BIND 9 and generates its configuration from a simple YAML file. DNS updates are authenticated using TSIG (HMAC-SHA512), with permissions restricted to individual DNS record names.
Configuration
Create a file named config.yml:
soa_mname: ns-dyn.example.com
soa_rname: hostmaster.example.com
keys:
dyndns: "BASE64_ENCODED_TSIG_SECRET"
acme: "ANOTHER_BASE64_ENCODED_TSIG_SECRET"
zones:
dyn.example.com:
home: dyndns
acme.example.com:
_acme-challenge: acme
This configuration:
- Creates authoritative DNS zones for
dyn.example.comandacme.example.com. - Allows the
dyndnskey to updatehome.dyn.example.com. - Allows the
acmekey to update_acme-challenge.acme.example.com.
The soa_mname and soa_rname settings specify the primary authoritative nameserver (= the server this is running on) and responsible party for the SOA record. For soa_rname, use the DNS representation of an email address (hostmaster.example.com corresponds to hostmaster@example.com).
Docker Compose
Create a docker-compose.yml:
services:
dns:
image: ghcr.io/mikegerber/rfc2136-dns-container:main
restart: unless-stopped
ports:
- "53:53/udp"
- "53:53/tcp"
volumes:
- ./config.yml:/etc/bind/rfc2136-dns-container.yml:ro
- dns-data:/var/bind/rfc2136-dns-container
volumes:
dns-data:
Start the server:
docker compose up -d
Check the logs:
docker compose logs -f dns
Port 53 must be available on the host for both UDP and TCP.
The dns-data volume stores zone files and dynamic updates, preserving DNS records across container restarts and upgrades.
DNS delegation
For public DNS use, configure the appropriate NS records at your parent zone or DNS provider to delegate the desired zone to this server.
ACME
You can use a DNS CNAME record to delegate an ACME DNS-01 challenge to a record served by this service, allowing certificate validation without modifying the original zone's TXT records.
E.g.
_acme-challenge.example.com. CNAME _acme-challenge.acme.example.com.
Creating keys
TSIG secrets must be base64-encoded keys. Generate a key using:
tsig-keygen -a hmac-sha512 dyndns
Repeat for each key and copy the generated secret values into the YAML configuration. Note that
the key name must match on client and server.
Keep this configuration private: It contains credentials that authorize DNS updates.
Testing
Query the authoritative server:
dig @127.0.0.1 dyn.example.com SOA
To test a dynamic update, create a TSIG key file containing the same key and secret as configured above:
key "dyndns" {
algorithm hmac-sha512;
secret "BASE64_ENCODED_TSIG_SECRET";
};
Then run:
nsupdate -k dyndns.key
Enter:
server 127.0.0.1
zone dyn.example.com
update add home.dyn.example.com. 60 A 192.0.2.123
send
Verify the record:
dig @127.0.0.1 home.dyn.example.com A +short
Expected result:
192.0.2.123
The server supports standard RFC 2136 clients, including nsupdate and ACME clients with RFC 2136 DNS provider support.
Notes
- The server is authoritative only. Recursive DNS queries are disabled.
- DNS zone transfers are disabled.
- Dynamic update permissions are restricted to the configured record names.
- A separate TSIG key can be assigned to each record name.
- Zone files are initialized automatically if they do not exist.
- Existing zone files are preserved on restart.
- The image includes a health check that queries the local DNS server without depending on any configured zone.