Setup an authoritative DNS server using bind9, connected to a Pi-hole instance that is forwarded to an unbound DNS server. The approach is to be your own DNS rather than forwarding all your DNS traffic out to the wide-world web. The Docker networking settings create a connection between the three containers running on each server.
The general flow for the DNS queries is: Client -> BindDNS -> Pi-hole DNS -> Unbound DNS. Your environment may include a router other network device as well.
These procedures assume you are using Ubuntu Linux. The steps were tested on Ubuntu 22.04.3 LTS (Jammy Jellyfish). It is recommended the target server for this installation use either static IP addresses or a DHCP reservation to achieve the same result.
Docker and docker compose are also required. The steps below will help setup the Linux machine for success.
sudo sed -i 's/^#DNSStubListener=.*/DNSStubListener=no/g' /etc/systemd/resolved.conf
sudo ln -sf /run/systemd/resolve/resolv.conf /etc/resolv.conf
sudo systemctl restart systemd-resolved
Steps adopted from official Docker documentation. If you're looking for fewer steps, there is a shorter version from Docker here. Prepare the repository:
sudo apt-get update
sudo apt-get install ca-certificates curl gnupg
sudo install -m 0755 -d /etc/apt/keyrings
curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo gpg --dearmor -o /etc/apt/keyrings/docker.gpg
sudo chmod a+r /etc/apt/keyrings/docker.gpg
echo \
"deb [arch="$(dpkg --print-architecture)" signed-by=/etc/apt/keyrings/docker.gpg] https://download.docker.com/linux/ubuntu \
"$(. /etc/os-release && echo "$VERSION_CODENAME")" stable" | \
sudo tee /etc/apt/sources.list.d/docker.list > /dev/null
sudo apt-get update
sudo apt-get install docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin
Verify by a quick run of your favorite hello-world app:
sudo docker run hello-world
Create the docker group:
sudo groupadd docker
Add your favorite user to the docker group:
sudo usermod -aG docker $USER
Once completed, you can log out and log back in so that your group membership is checked again. If you're feeling fancy, just type bash
to run up a new shell and keep going.
git clone https://github.com/dronebeelinux/dnstrio.git
Reference: Official ubuntu/bind9 Docker Hub
cd ./dnstrio
mkdir -p ./bind/var/cache/bind
find ./bind -type d -exec chmod -R 755 {} \;
The settings in the env1.env
and env2.env
files can be updated to suite your needs based on your networking and hostname requirements. If no changes are made, the result will be a new domain with the name example.internal
. Use env1.env
on the first DNS server and env2.env
(steps below) on the second DNS server.
Make updates for the first environment. keep it simple and don't get crazy.
Set the environment to match the server instance you are working on:
export DNSENV=env1
Edit the environment as needed:
vi ${DNSENV}.env
The replace_env.sh
script will find and replace values from the environment files configured above and put them into usable files across the containers and for docker compose.
Update permissions to include execute on the script:
chmod +x replace_env.sh
Update the example zone configuration:
./replace_env.sh bind/etc/bind/zones/db.domain_example.internal ${DNSENV}.env bind/etc/bind/zones/db.domain.internal
Update the local zone config file:
./replace_env.sh bind/etc/bind/named.conf_example.local ${DNSENV}.env bind/etc/bind/named.conf.local
Update docker environment:
./replace_env.sh .env_example ${DNSENV}.env .env
Update permissions on bind files. Do NOT complete these steps until you're sure you're done with modifying the bind config and zone files. NOTE: the user id 100 and gid 101 will not match to the "bind" user on the Ubuntu Linux host but will inside of the Docker container.
sudo chown -R 100:101 ./bind
The original docker-compose.yaml for this project was originally pulled from here. Minor modifications have been made to integrate the three DNS servers into one project.
The default installation of pi-hole will not allow connections to many websites that contain ads, including ye old social media sites. If you find you are blocked right away, check the pihole query log for details.
NOTE: The password is set as "password" (no quotes). Use the below command if you want to change it to something special.
echo "password" > ./pihole/secrets/web_password.txt
Reference: Unbound from Matthew Vance
Get root hints:
mkdir -p ./unbound/etc/unbound/var
dig +bufsize=1200 +norec NS . @a.root-servers.net | tee ./unbound/etc/unbound/var/root.hints
Run the same steps again on your second DNS server. Be sure to use the env2.env file instead of env1.env. Remember, one is none and two is one.
Make updates for the second environment. keep it simple and don't get crazy and don't overlap the IP ranges with the first.
Set the environment to match:
export DNSENV=env2
Edit the environment as needed:
vi ${DNSENV}.env
From here, scroll back up and run the commands again for the second environment. Look for "update the example zone configuration" above.
Ready? Go!
docker compose up -d
Check your favorite website to make sure DNS resolves as expected. If you know the local IP, this fancy command isn't really needed:
dig webhamster.com @$(hostname -I | awk '{print $1}')
If you can't dig it, try nslookup:
nslookup webhamster.com $(hostname -I | awk '{print $1}')
Don't forget to check your new local domain:
source .env
dig ns1.$DOMAIN.$TLD @$(hostname -I | awk '{print $1}')
Consider these steps after your DNS is up and running
Use your DHCP settings on your router or wherever your friendly, neigborhood DNS settings are stored. If you made it this far, you probably know what this means and what to do. If you're not sure, check out this site for more details on how to get started: Fix my router DNS settings
If you have another pi-hole running on your network and need to export/import the settings, checkout the official pi-hole guide here:
Other ideas to consider for this project:
What would you do? Any suggestions? Feel free to contribute or share your thoughts. I am always open to new ideas!