Following Part 1 of the series, the first component to be set up is the AdGuard Home DNS server. I chose this because it also blocks ads and unwanted services which enables my VPN clients to have a better web browsing experience. Aside from this, I get a useful GUI to view resolutions requests and to configure custom domains in an easy-to-use manner. I did contemplate utilizing dnsmasq but finally decided on AdGuard Home.

The Docker Compose file and configuration of AdGuard Home is located in /containers/adguardhome base folder.

/containers/adguardhome/docker-compose.yaml

services:
  adguardhome:
    image: adguard/adguardhome:latest
    container_name: adguardhome
    restart: unless-stopped
    volumes:
      - '/containers/adguardhome/work:/opt/adguardhome/work'
      - '/containers/adguardhome/config:/opt/adguardhome/conf'
    networks:
      - webproxy
    ports:
      - '192.168.200.1:3000:30003/tcp' # initial setup port

      - '192.168.250.1:53:53/tcp' # listen for DNS on webproxy interface (tcp)
      - '192.168.250.1:53:53/udp' # listen for DNS on webproxy interface (udp)

      - '192.168.200.1:53:53/tcp' # listen for DNS on wireguard interface (tcp)
      - '192.168.200.1:53:53/udp' # listen for DNS on wireguard interface (udp)

networks:
  webproxy:
    external: true

In this setup, I decided to have AdGuard Home listen on 3 interfaces - the Docker webproxy interface so I can force Docker to route all DNS requests to THIS DNS. - the wireguard interface so I can give the option for all my Wireguard clients to route all DNS requests to THIS DNS.

With this done, I run docker compose up to bring this container up and for it to create the necessary folders. With that out of the way, from my Wireguard client, I connect to http://192.168.200.1:3000/ allowing me to configure AdGuard Home. I always change the Admin Web Interface listen port from 80 to 8000. Ensure the DNS server is set to listen on ALL interfaces port 53. The last step is to choose a strong username and password combination. Continue with the setup until the launch dashboard option. Since we haven’t exposed port 8000, our attempt to connect to it will fail.

AdGuard Home Setup
AdGuard Home Initial Setup

With the setup done, I terminate this container using CTRL+C and edit /containers/adguardhome/docker-compose.yaml again to remove the '192.168.200.1:3000:30003/tcp'. I no longer need it since I will be using caddy to access the AdGuard Home Admin UI.

I start the container back up using docker compose up -d to have it running perpetually.


Firewall

My VPS runs ufw as the firewall frontend so I have a rule that allows DNS traffic to traverse between the interfaces without being blocked. As the DNS server is not exposed on any of the public IP, this approach ensures there is no situation where a service or container will not be able to resolve any DNS queries

ufw allow proto udp from any to any port 53
ufw allow proto tcp from any to any port 53

The next step is to force Docker to use our new DNS server for all its requests. This is a key item to ensure any resolution to custom domain names succeeds and returns the correct IP address for the domain.


DNS for Docker

Create or edit the file /etc/docker/daemon.json and ensure a similar line to the following exists in it

{
  "dns": [
    "192.168.250.1"
  ]
}

using the IP address of the webproxy interface to force all containers to use this specific DNS instance. Make sure to restart Docker for these changes to take effect.


DNS for VPS

The last step is to force the VPS to route all DNS requests to this AdGuard Home instance. My instance uses systemd-networkd with systemd-resolved to set the IP address so I modified my existing network configuration file at /etc/systemd/network/20-wired.network with the following contents

[Match]
Name=enp1s0

[Network]
DHCP=yes
IPv6PrivacyExtensions=yes
Address=2404:1:2:3::1001/128
Address=2404:1:2:3::9999/128
DNS=192.168.250.1 # IP address of the `webproxy` interface

I prefer to reboot my VPS after all these changes to make sure there is nothing lingering in the background. After a successful reboot, I verify the availability by using the dig command to resolve a domain of my choice and checking the AdGuard home logs for the query.

After this, my VPS will use AdGuard Home for all its DNS resolution. With this in place, we can move on to

Now we can proceed to Part 3 of the guide, setting up the Smallstep Certificate Authority server.