Skip to content
appsgit

Deploy guide

How to self-host AdGuard Home with Docker Compose

AdGuard Home Docker Compose setup for network-wide ad blocking: port 53 and systemd-resolved, setup wizard, encrypted DNS, router config, backups, upgrades.

  • Updated
  • Beginner
  • About 15 minutes

You will need

  • 1 vCPU / 256 MB RAM (a Raspberry Pi is enough)
  • Docker + Docker Compose v2
  • A static LAN IP for the server
  • Access to your router's DHCP or DNS settings

What is AdGuard Home?

AdGuard Home is a network-wide ad and tracker blocker that works as a DNS server. Point your router at it and every device on the network, including phones, smart TVs and game consoles, gets ads, trackers and malware domains blocked without installing anything. It also offers encrypted upstream DNS, per-client rules, parental controls and an optional DHCP server. AdGuard Home is open source under the GPL-3.0 license.

Requirements

  • Any small Linux machine. A Raspberry Pi or a 1 vCPU VM with 256 MB of RAM handles a household easily.
  • Docker Engine and Docker Compose v2.
  • A static LAN IP for the server (set a DHCP reservation in your router), because every device will send DNS queries to it.

Step 1: Prepare the server

This guide assumes Ubuntu 24.04 with Docker installed from the official Docker Engine guide.

Ubuntu's systemd-resolved already listens on port 53, so Docker cannot bind it. The official AdGuard Home docs fix this by disabling the stub listener:

sudo mkdir -p /etc/systemd/resolved.conf.d
printf '[Resolve]\nDNS=127.0.0.1\nDNSStubListener=no\n' | sudo tee /etc/systemd/resolved.conf.d/adguardhome.conf
sudo mv /etc/resolv.conf /etc/resolv.conf.backup
sudo ln -s /run/systemd/resolve/resolv.conf /etc/resolv.conf
sudo systemctl reload-or-restart systemd-resolved

Then create the folders:

mkdir -p ~/adguardhome/work ~/adguardhome/conf && cd ~/adguardhome

Step 2: Create the Docker Compose file

Save this as docker-compose.yml:

services:
  adguardhome:
    image: adguard/adguardhome:v0.107.79
    container_name: adguardhome
    restart: unless-stopped
    ports:
      - "53:53/tcp"
      - "53:53/udp"
      - "3000:3000/tcp"
      # Encrypted DNS, once you have a certificate:
      # - "853:853/tcp"
      # - "853:853/udp"
    volumes:
      - ./work:/opt/adguardhome/work
      - ./conf:/opt/adguardhome/conf

The two volumes keep the query log, statistics and filter lists (work) and the AdGuardHome.yaml configuration (conf). Only DNS and the web UI are published. Add the encrypted DNS ports when you need them.

If you want AdGuard Home to be your DHCP server too, the official docs require host networking instead of port mappings: replace the ports: block with network_mode: host.

Step 3: Start and open the app

docker compose up -d

Open http://YOUR_SERVER_IP:3000 to start the setup wizard. On the "Admin Web Interface" screen, set the port to 3000 so it matches the Compose mapping (the default of 80 is not published here). Leave the DNS server on port 53, create the admin username and a long password, and finish.

Now sign in and open Filters, DNS blocklists to see the default AdGuard DNS filter. Under Settings, DNS settings, pick encrypted upstreams such as https://dns.quad9.net/dns-query. Finally, set your router's DHCP DNS server to the AdGuard Home IP, or point one device at it first to test.

Step 4: Put it behind HTTPS

The admin panel can go behind Caddy on the same host:

adguard.example.com {
    reverse_proxy 127.0.0.1:3000
}

Once that works, change the UI mapping to "127.0.0.1:3000:3000/tcp". Docker-published ports bypass ufw, so firewall rules alone do not hide the panel. The same applies to port 53: on a home network behind NAT that is fine, but on a VPS bind it to a VPN address, for example "100.64.0.10:53:53/udp" for Tailscale, so you do not run an open resolver. For DNS-over-HTTPS or DNS-over-TLS, add a certificate under Settings, Encryption settings and publish 853.

Backups and upgrades

Everything lives in the two folders. A short stop gives a consistent copy:

docker compose stop && tar czf adguard-$(date +%F).tgz conf work && docker compose start

conf/AdGuardHome.yaml alone restores all settings, clients and filter choices. To upgrade, change the image tag and run:

docker compose pull && docker compose up -d

Use the image tag for updates; the built-in updater in the web UI is meant for the standalone binary, not Docker.

Troubleshooting

  • "address already in use" on port 53: systemd-resolved is still running its stub listener. Recheck Step 1, or find the process with sudo ss -lunp | grep :53.
  • Ads still appear on one device: the browser or device uses its own DNS-over-HTTPS resolver. Turn off "secure DNS" in the browser settings so queries go through AdGuard Home.
  • Some sites break: check Query Log for the blocked domain and add it to the allowlist with one click.
  • Server itself cannot resolve names: the container is down while the host points at 127.0.0.1. Start it again, or add a fallback upstream in the resolved.conf.d file.

Next steps

Add more blocklists, set per-client rules for kids' devices, enable DNS-over-HTTPS for phones outside the house through a VPN, and run a second instance on another machine so DNS keeps working during maintenance.

Spotted something out of date? Tell us and we will update the guide.

FAQ

AdGuard Home questions

Still curious? Email info@appsgit.com.

What ports does AdGuard Home use?

Port 53 TCP and UDP for DNS, port 3000 for the first-run setup wizard, and port 80 for the admin panel by default. Optional ports are 443 for DNS-over-HTTPS, 853 for DNS-over-TLS and DNS-over-QUIC, 5443 for DNSCrypt, and 67/68 UDP for the DHCP server.

What is the default AdGuard Home login?

There is no default login. The setup wizard on port 3000 asks you to create the admin username and password before the dashboard is available.

Is AdGuard Home free?

Yes. AdGuard Home is free and open source under the GPL-3.0 license. It is a separate product from AdGuard's paid apps and browser extensions.

Pi-hole vs AdGuard Home: which is better?

Both block ads and trackers for every device on your network. AdGuard Home has DNS-over-HTTPS, DNS-over-TLS and DNS-over-QUIC built in, per-client settings and a single binary with no extra components. Pi-hole has a larger community and a long track record. For encrypted DNS without add-ons, AdGuard Home is the simpler choice.

Why does Docker fail to bind port 53?

On Ubuntu, systemd-resolved runs a DNS stub listener on 127.0.0.53:53. Disable the stub listener with a drop-in config, as shown in this guide, and restart systemd-resolved before starting the container.

Can I run AdGuard Home on a VPS?

Yes, but never leave port 53 open to the whole internet, because an open resolver gets abused for DDoS amplification. Bind DNS to a VPN interface such as WireGuard or Tailscale, or allow only your own IP addresses in AdGuard Home's access settings.