Self-Hosting πŸ“– 12 min read

AdGuard Home Deployment

AdGuard Home is an open-source DNS server that blocks ad and tracking domains for every device on your network. It does the same core job as Pi-hole, and it builds in encrypted DNS (DNS-over-HTTPS, DNS-over-TLS and DNS-over-QUIC) and per-client settings, so you don't run a separate proxy for them. This guide covers installing it with the official script or Docker, the setup wizard, encrypted upstreams, blocklists, per-client rules and the port 53 conflict that trips up most first installs.

What you need: a Linux machine on your network with sudo access and a fixed IP address (a DHCP reservation on the router works), plus Docker if you use the container method. To point every device at it, you also need access to your router's DHCP settings.

Versions: written for AdGuard Home v0.107.79, the latest stable release on the AdGuard Home releases page when this page was updated. Installation steps follow the project's Getting Started and Docker wiki pages.

Pi-hole vs AdGuard Home: the real differences

Both block the same kinds of domains, accept common blocklist formats and show a query log. The differences that usually decide it:

  • Encrypted DNS is built in. AdGuard Home can send its upstream queries over DoH, DoT or DoQ, and can serve those protocols to your own devices. Pi-hole forwards plain DNS; for encrypted upstreams its documentation describes running a separate proxy such as cloudflared next to it.
  • Per-client settings. AdGuard Home lets you give each device its own blocklists, Safe Search, blocked services and upstream servers from one screen. Pi-hole does this through group management, which takes more steps to set up.
  • Documentation and guides. Pi-hole has been around longer, and more third-party blocklist guides and forum answers are written with it in mind. Custom regex rules written for Pi-hole may need rewriting for AdGuard Home's filtering syntax.

If you haven't picked yet, the Pi-hole Deployment Guide covers the same setup with Pi-hole v6.

Quick Installation

Terminal window with the commands from the section Quick Installation
Download, extract and move AdGuard Home into /opt. Pick the arm64 archive on a 64-bit ARM board.

On Linux (Any Recent Distro)

The automated installer from the project README downloads the latest stable release into /opt/AdGuardHome and registers it as a service:

curl -s -S -L https://raw.githubusercontent.com/AdguardTeam/AdGuardHome/master/scripts/install.sh | sh -s -- -v

Or install it manually:

# Download the latest stable release (use the arm64 archive on 64-bit ARM)
wget https://static.adguard.com/adguardhome/release/AdGuardHome_linux_amd64.tar.gz

# Extract
tar xvf AdGuardHome_linux_amd64.tar.gz

# Move to /opt
sudo mv AdGuardHome /opt/

# Install and start as a service
cd /opt/AdGuardHome
sudo ./AdGuardHome -s install

Other service commands are -s start, -s stop, -s restart, -s status and -s uninstall. On Fedora and its derivatives, the Getting Started page says to install into /usr/local/bin instead, to avoid SELinux permission problems.

Docker Method

If the host already runs containers (see the Docker Installation Guide for Docker Engine itself), this is the wiki's command with the image pinned and only the ports a home setup needs:

Set LAN_IP to the host’s reserved private LAN address, for example export LAN_IP=192.168.1.100. Keep DNS port 53 closed on the internet-facing router and provider firewall; Docker port publishing can bypass some host firewall rules.

docker run -d --name adguardhome \
 --restart unless-stopped \
 -v /srv/adguard/work:/opt/adguardhome/work \
 -v /srv/adguard/conf:/opt/adguardhome/conf \
 -p "${LAN_IP:?Set LAN_IP}:53:53/tcp" -p "${LAN_IP:?Set LAN_IP}:53:53/udp" \
 -p 127.0.0.1:8080:80/tcp -p 127.0.0.1:3000:3000/tcp \
 adguard/adguardhome:v0.107.79
  • work holds the query log, statistics and filter data; conf holds AdGuardHome.yaml. Create both directories first.
  • Port 3000 is only used by the first-run wizard; 80 serves the web interface afterwards.
  • Add -p 443:443/tcp -p 443:443/udp -p 853:853/tcp -p 853:853/udp only if you will serve DoH, DoT or DoQ yourself (see below).
  • With Docker's bridge network, AdGuard Home sees every client as the bridge address (something like 172.17.0.1). To see real client IPs, or to use its DHCP server, host networking is an alternative, but removes the protection of the host port bindings shown here. Configure explicit trusted listening addresses and firewall restrictions before exposing the service.
  • The Docker image doesn't update itself. To update, change the tag to a newer release, then stop, remove and recreate the container with the same volumes.

Initial Setup

For Docker, run ssh -N -L 3000:127.0.0.1:3000 -L 8080:127.0.0.1:8080 user@adguard-host, then open http://localhost:3000. In the container wizard, listen on all container interfaces for DNS and web: the host bindings above restrict exposure. After setup use http://localhost:8080 through the same tunnel. For a native installation, reach port 3000 only over a trusted LAN or VPN and restrict the listening addresses in the wizard.

The setup wizard covers:

  1. Admin web interface - which address and port the dashboard listens on (port 80 by default)
  2. DNS server - which address and port DNS listens on (port 53)
  3. Admin credentials - the username and password for the dashboard

If the wizard reports that port 53 is already in use, the cause on Ubuntu is almost always systemd-resolved. The wizard shows a Fix button for this on a native install; in Docker you have to fix it on the host. Both cases are covered under Port 53 Already In Use.

Query logs can expose household browsing metadata. Tell users what is recorded, choose an appropriate retention period in the dashboard, and restrict access to the logs and backups.

Configure Your Network

Point your devices at AdGuard Home's IP address for DNS, the same way you would with Pi-hole. Give the machine a fixed address first (a DHCP reservation on the router is the easiest way).

Option 1: Router DHCP

Set your router to hand out AdGuard Home's IP as the DNS server. Every device that gets its address from the router then uses it. Don't add a public resolver as the second DNS server, or some queries will skip filtering.

Option 2: Per-device

Set DNS manually on each device. The Getting Started page has steps for Windows, macOS, Android and iOS.

Option 3: AdGuard as DHCP

AdGuard Home can be your DHCP server, which also lets the dashboard show device names instead of bare IP addresses. Turn off DHCP on the router first. In Docker this needs --network host.

Settings β†’ DHCP settings β†’ Enable

Check that it works: on a device that should now use AdGuard Home, run nslookup example.com YOUR_IP. An address in the reply means AdGuard Home is answering DNS queries. Then load a few websites on that device and open the Query Log: the requests should appear within a few seconds. If they don't, the device is still sending queries somewhere else, usually a second DNS server set on the router, a DNS server fixed in the device's own network settings, or the browser's secure DNS setting.

Encrypted Upstream DNS

Plain DNS travels unencrypted, so your ISP or anyone on the path can see and alter the domains you look up. An encrypted upstream protects the DNS hop between AdGuard Home and that resolver. The resolver still sees the queries; ordinary client-to-AdGuard DNS may remain unencrypted. Destination IP addresses and other connection metadata can still reveal activity. DNS encryption alone does not provide anonymity.

Editor window showing Upstream DNS servers from this section
Encrypted upstreams, one per line. Mixing in plain DNS servers such as 9.9.9.9 would send those queries unencrypted.

Setting Upstream DNS

Settings β†’ DNS settings β†’ Upstream DNS servers. Enter one server per line:

# Quad9 over DNS-over-HTTPS
https://dns.quad9.net/dns-query

# Google over DNS-over-HTTPS
https://dns.google/dns-query

# Quad9 over DNS-over-TLS
tls://dns.quad9.net

With several servers listed, the upstream mode decides how they are used. Load-balancing queries one server at a time and favours the ones that answer fastest with the fewest failures; Parallel requests asks all of them and takes the first answer; Fastest IP address waits for all of them and can slow lookups down if one server is unresponsive.

Avoid mixing plain DNS servers such as 9.9.9.9 into the same list "for reliability". Any query that goes to them is unencrypted, which undoes the point of the encrypted entries. Listing two encrypted providers gives you redundancy without that trade-off.

Bootstrap DNS

AdGuard Home has to resolve hostnames like dns.quad9.net before it can use them. That's what the Bootstrap DNS servers field on the same page is for; put plain IP resolvers there, for example 9.9.9.9 and 1.1.1.1.

Serving Encrypted DNS Yourself

AdGuard Home can also act as a DoH, DoT and DoQ server, so phones can use it as their "Private DNS". The Encryption wiki page points out that this mainly makes sense for a server with a public address, because inside your own LAN the traffic isn't crossing anyone else's network. You need:

  1. A domain name pointing at the server.
  2. A TLS certificate for it, for example from Let's Encrypt with Certbot or lego. The wiki uses a DNS challenge: sudo certbot certonly --manual --preferred-challenges=dns --preferred-chain="ISRG Root X1". Certificates from the manual DNS challenge don't renew automatically, so use a DNS plugin or lego if you want renewals handled for you.
  3. In Settings β†’ Encryption settings, paste the contents of fullchain.pem into Certificates and privkey.pem into Private key, enter the server name and save.

Don't run an open resolver on the internet. Before exposing ports 443 or 853, restrict who may query the server under Settings β†’ DNS settings β†’ Access settings (allowed clients), and expect scanners to find it. If a reverse proxy such as Nginx terminates TLS in front of AdGuard Home, the wiki explains the trusted_proxies setting (the Nginx Web Server Setup covers the proxy side).

Blocklists

AdGuard Home starts with its own default list. Add more under:

Filters β†’ DNS blocklists β†’ Add blocklist

Commonly used additions:

  • OISD, a curated list that aims to keep false positives low
  • StevenBlack hosts, a unified hosts file built from several sources

Add lists one at a time and use each for a while before adding another. The bigger the combined list, the more likely it is to block something a streaming app, smart home device or work tool needs, and it's much easier to find the culprit when only one list changed.

Per-Client Settings

Settings β†’ Client settings β†’ Add client

For each client (by IP, MAC address or ClientID) you can:

  • Give it a friendly name that shows in the dashboard and query log
  • Turn on Safe Search and stricter lists, for example on a child's tablet
  • Disable filtering entirely, for a work laptop that must not have anything blocked
  • Block specific services, or use different upstream DNS servers

The Dashboard

The main dashboard shows:

  • Total queries over the selected period
  • Queries blocked (number and percentage)
  • Top blocked domains
  • Top clients
  • Top queried domains

The top clients and top queried domains lists are a quick way to spot a device that is unusually chatty.

Query Log

The query log shows every DNS request, which client made it and whether it was blocked, and by which rule. When something breaks after adding a blocklist, this is where you find the domain that got caught.

How long the log and statistics are kept is set under Settings β†’ General settings. Shorter retention keeps the log smaller and quicker to search; longer retention helps when you're tracking down an intermittent problem.

Common Issues

Terminal window with the commands from the section Common Issues
Freeing port 53: turn off the systemd-resolved stub listener, then point /etc/resolv.conf at the resolver's real file.

Port 53 Already In Use

Ubuntu runs systemd-resolved, which listens on 127.0.0.53:53, so AdGuard Home fails with bind: address already in use. Confirm with sudo lsof -i :53.

On a native install, try the Fix button in the setup wizard first. Otherwise (and always for Docker or Snap), the AdGuard Home FAQ fix turns off only 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

DNS=127.0.0.1 makes the host itself use AdGuard Home, because without the stub listener the old 127.0.0.53 nameserver no longer answers. After this, sudo lsof -i :53 should no longer list systemd-resolved. This approach keeps systemd-resolved running, which matters on Ubuntu because netplan and VPN clients rely on it.

Slow DNS Resolution

Encrypted upstreams add some latency compared with plain DNS. Caching (on by default) hides most of it after the first lookup. If lookups are slow or failing outright, check that the bootstrap servers are reachable, and that you're not using the Fastest IP address mode with an unresponsive upstream.

App/Service Breaks

Find the blocked domain in the query log and use the unblock option there, or add an allow rule under Filters β†’ Custom filtering rules, for example @@||example.com^. Some devices and apps stop working entirely if their tracking or update domains are blocked; you'll have to choose between blocking those domains and using that device.

Updates

Terminal window with the commands from the section Updates
Check the installed version first, then let the binary update itself.
# Check the installed version
/opt/AdGuardHome/AdGuardHome --version

# Update a native install from the command line
sudo /opt/AdGuardHome/AdGuardHome --update

On a native install, the web interface also shows an Update now button when a new release is out. Docker installs have auto-update disabled; update by moving to a newer image tag as described above.

Trade-offs Compared with Pi-hole

  • Community material: there are fewer third-party guides and forum threads for AdGuard Home problems than for Pi-hole, so you'll lean more on the project's own wiki.
  • Rule syntax: AdGuard Home uses its own filtering-rule syntax. Most hosts-style and Adblock-style lists work as-is, but hand-written regex rules from Pi-hole may need translating, and not every one has a direct equivalent.
  • Memory: both are light enough for a Raspberry Pi. Usage depends mostly on the size of your blocklists and how long you keep logs, so check it on your own hardware if you're on a low-memory board.

Should You Switch?

If encrypted DNS or per-device rules matter to you and you'd rather not run and update a separate DoH proxy, AdGuard Home is the simpler choice. If Pi-hole is working and you don't need those features, there's little reason to replace a working setup. Whichever you run, it's a good fit for an always-on board like the one in the Raspberry Pi Setup Guide.