Our local setup for running a recent BIND version via Docker.
Go to file
2024-06-11 15:53:41 -04:00
cache add directories 2023-02-25 15:30:09 -05:00
cfg enable IPv6 in the options 2024-06-11 15:53:41 -04:00
log/named add directories 2023-02-25 15:30:09 -05:00
zones point all IPs to diagonal.blacka.com's IPs except zeke.blacka.com 2024-05-15 22:14:44 -04:00
.gitattributes remove accidental secondary; git-crypt setup 2023-02-24 19:58:57 -05:00
.gitignore ensure zones/secondary exists 2023-02-25 19:48:12 -05:00
docker.named.service we cannot successfully pull from docker.io without DNS 2023-02-26 14:32:21 -05:00
README.md add wrapper for running named-compilezone, update README 2024-06-11 15:52:30 -04:00
run_bind_container.sh Merge branch 'main' of /home/davidb/site/blacka.com/software/repos/docker_bind into main 2023-02-26 14:47:31 -05:00
run_named-checkconf.sh add/adjust docker exec scripts 2023-02-26 10:08:23 -05:00
run_named-compilezone.sh add wrapper for running named-compilezone, update README 2024-06-11 15:52:30 -04:00
run_rndc.sh add/adjust docker exec scripts 2023-02-26 10:08:23 -05:00
setup.sh add setup.sh 2023-02-25 19:35:27 -05:00

blacka.com DNS service

This repo and directory consists of the DNS service for blacka.com. The goals of this service are:

  1. Host the primary zones we want.
  2. DNSSEC-sign those primary zones, if desired.
  3. Provide local recursive service for the host itself.

It was the revamped DNS service for zeke.ecotroph.net, and thus served zones by the collection of owners of zeke. However, zeke has reached End-of-Life. In the future, the zeke operators will operate their own (virtual) environments independently.


In the past, we just ran the version of BIND that came with our distribution (at this moment, that is CentOS 7, which translates to bind 9.11.) This new configuration runs a very recent version of BIND 9 via a docker image produced by ISC themselves. We started with 9.18.12 and now are up to 9.18.20.

This docker image imposes a few requirements:

  • Internally, the image runs named as the bind user (104:105). Since we bind-mount directories, we do need those directories owned by whatever internal UID it is using.
  • We need some way to ensure that our container is run on system reboots, etc. Here we chose to use systemd to do this, although that is not ideal.
  • Presumably the normal way to do logging for a docker container is to use the standard journal service, although this image is set up to bind-mount /var/log. On the other hand, the standard command uses the -g flag, which is "debug" mode, and causes all of the logs to go to stderr.
  • We do want named to stay in the foreground here. Fortunately, there have always been command line options that do this (-g and -f). Thus, in order to log to /var/log, we supply a different command: /usr/sbin/named -f -u bind. This will run in the foreground, and run as the internal bind user.


We can see it here: https://blacka.com/git/docker_bind.git.


We have in this repo:

  • named configurations. I've broken this up into sections (options, keys, logging, primary, secondary, etc.), which all just get included in the primary named.conf. It isn't tricky.
  • "keys". Well, mostly TSIG keys. Those are encrypted with git-crypt. With a key that is ... somewhere. I've saved it in my password manager, but it can be extracted from the current checkout in /etc/bind with cd /etc/bind; git-crypt export-key /tmp/docker_bind_crypto.key. git-crypt doesn't seem to come via RPM and yum, but I built it and installed it into /usr/local/bin on my virtual host (and zeke when this was first set up.)
  • zone files. This is now just the blacka.com domains, which is currently just blacka.com itself.
  • A script to launch the container (run_bind_container.sh).
  • A script to use as the internal "command" (cfg/run.sh) -- it isn't config, but we need to bind-mount it. It could possibly be moved to cache.
  • A helper script to run rndc that just runs that inside the container itself (via a docker exec). You would need to be in the docker group to run it. Another few helper scripts to run other command line tools: named-checkconf, named-compilezone.
  • A helper script to prepare your host to run this container and properly work, in case we want to do this install again (setup.sh).


Working with github.com or https://blacka.com/git (gitea currently) is tricky as a different user, as git will want to use your own SSH keys. Thus some of this advice doesn't really work as stated. Instead of cloning the repo as the bind user, we clone it as ourselves and copy it to the expected location.

  1. Clone this repo to /etc/bind (clone in /etc -- we want the working copy to be /etc/bind.)
  2. Create a user to match the internal user (uid 104): useradd -u 104 -g 105 -M --no-log-init bind. The setup.sh will do this.
  3. Change the ownership of everything under /etc/bind to the bind user and group: chown -R 104:105 /etc/bind.
  4. Copy the supplied systemd unit file to /etc/systemd/system, and systemctl enable docker.bind.service, then systemctl start docker.bind.service.

Note that in the future, we will attempt to adjust this to use podman natively instead of docker.

Zone Changes

All of our zone files are now in this git repo, so we can just make changes and commit them, assuming you have write access to the local repo, that is. The bind user should be able to do it, though. Once you've changed your zone, you could bounce the service via systemctl, or we could use rndc. I've made a little script that will do this with docker exec, /etc/bind/run_rndc.sh. Thus:

sudo -u bind -s
cd /etc/bind/zones
vi <zonefile> # remember to update the serial
git commit -a <zonefile>
git push
cd ..
./run_rndc.sh reload <zone>

Which would work, if and only if as bind the git push actually works.

Instead, we need to develop a sustainable way to update the zone. Currently we update in the repo somewhere, git pull the changes to a local working copy, and copy the zone file into place. This is not ideal.


More modern BIND releases have changed the configuration for this. Note how your zone is signed is based on a dnssec-policy block (I've put those in cfg/named.dnssec.conf). Then, in your BIND configuration, you add:

dnssec-policy "default_alg13";
inline-signing yes;

in your zone block. After restarting/reconfiguring BIND, it will create a <zonefile>.signed and <zonefile>.signed.jnl file, and start serving a DNSSEC signed version of the zone. It will then take care of resigning activities, key rollovers etc.

Zone Files

We can find the zone files in /etc/bind/zones, although note that your zone may be in BIND's raw format. If you want to see the contents, you can use named-compilezone for that (either using a version inside the container or not):

named-compilezone -f raw -F text -o - blacka.com /etc/bind/zones/blacka.com.signed

If using the script that runs the version in our container, note that you may have to use the paths that work inside the container. The current script mounts your current working directory, so you can use run_named_compilezone.sh ./some.zone, but not run_named_compilezone.sh /etc/named/zones/blacka.com.

That said, we are probably better off just using the version that comes with our OS, and not using the container.