AdGuard Home is a self-hosted DNS server that blocks ads and trackers for every device that uses it, and it can also serve encrypted DNS (DNS-over-HTTPS, DNS-over-TLS and DNS-over-QUIC) out of the box. That makes it a good fit for a VPS: phones and laptops can use it from anywhere over an encrypted connection. In this tutorial you will install AdGuard Home on Ubuntu 24.04, finish the setup wizard securely, configure upstream servers and blocklists, and enable DNS-over-HTTPS and DNS-over-TLS with a Let's Encrypt certificate.
Prerequisites
To follow this guide you need:
- A server running Ubuntu 24.04 LTS with a public IP address, for example a CubePath VPS. 1 GB of RAM is enough.
- A non-root user with
sudoprivileges and UFW enabled with SSH allowed. - A domain name with an
Arecord pointing to the server, used for the TLS certificate. This guide usesdns.example.com; replace it with your own name. - The public IP address of your home or office network, referred to as
your_client_ip, if you also want to use plain DNS on port 53.
Step 1 - Freeing port 53 from systemd-resolved
Ubuntu 24.04 runs systemd-resolved, whose stub listener occupies port 53 on 127.0.0.53. AdGuard Home needs that port, so disable the stub listener and point the system to AdGuard Home instead.
Create a drop-in configuration file:
sudo mkdir -p /etc/systemd/resolved.conf.d
sudo nano /etc/systemd/resolved.conf.d/adguardhome.conf
[Resolve]
DNS=127.0.0.1
DNSStubListener=no
Replace /etc/resolv.conf, which points to the stub, with the file that lists the real servers, and restart the service:
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
Confirm that nothing listens on port 53 any more:
sudo ss -lnup 'sport = :53'
The command should print only the header line. Name resolution on the server will fail until AdGuard Home is running in Step 3, so continue straight on.
Step 2 - Installing AdGuard Home
AdGuard Home is distributed as a single binary. Download the latest release for your architecture (use linux_arm64 on ARM servers) and extract it to /opt:
cd /tmp
curl -fsSLO https://github.com/AdguardTeam/AdGuardHome/releases/latest/download/AdGuardHome_linux_amd64.tar.gz
sudo tar -C /opt -xzf AdGuardHome_linux_amd64.tar.gz
Register it as a systemd service. The built-in installer creates the AdGuardHome unit and starts it:
sudo /opt/AdGuardHome/AdGuardHome -s install
Check the service:
systemctl status AdGuardHome --no-pager
● AdGuardHome.service - AdGuard Home: Network-level blocker
Loaded: loaded (/etc/systemd/system/AdGuardHome.service; enabled; preset: enabled)
Active: active (running) since ...
Until you finish the setup wizard, AdGuard Home only serves the wizard on port 3000.
Step 3 - Running the setup wizard through an SSH tunnel
The wizard lets anyone who reaches it create the admin account, so do not open port 3000 in the firewall. Instead, forward it over SSH from your own computer:
ssh -L 3000:127.0.0.1:3000 your_user@your_server_ip
Keep that session open and browse to http://localhost:3000 on your computer. In the wizard:
- Admin web interface: keep All interfaces and port 3000. You will reach it through the tunnel and later over HTTPS.
- DNS server: keep All interfaces and port 53.
- Authentication: create an admin user with a strong password.
- Finish the wizard and log in.
AdGuard Home writes its configuration to /opt/AdGuardHome/AdGuardHome.yaml. Test DNS from the server:
dig @127.0.0.1 cubepath.com +short
dig @127.0.0.1 doubleclick.net +short
0.0.0.0
The first command returns the site's address, and the ad domain returns 0.0.0.0. If dig is missing, install it with sudo apt install bind9-dnsutils.
Step 4 - Configuring upstream servers
AdGuard Home forwards every query that is not blocked to its upstream servers. Using encrypted upstreams prevents your hosting network from reading or modifying those queries. Open Settings > DNS settings and, under Upstream DNS servers, enter one server per line:
https://dns.quad9.net/dns-query
tls://one.one.one.one
Under Bootstrap DNS servers, which are used only to resolve the upstream hostnames above, enter plain IP addresses:
9.9.9.9
1.1.1.1
Select Load-balancing as the upstream mode, then click Test upstreams and Apply.
On the same page, under DNS server configuration, set a Rate limit (the default of 20 requests per second per client is reasonable) and enable DNSSEC. Under DNS cache configuration, you can enable Optimistic caching so cached answers are served while they are refreshed in the background.
Step 5 - Adding blocklists and custom rules
Open Filters > DNS blocklists. The AdGuard DNS filter is enabled by default. Click Add blocklist > Choose from the list to add curated lists, or Add a custom list to paste a URL. A small set of well maintained lists is better than many overlapping ones.
To block or allow single domains, open Filters > Custom filtering rules and use AdGuard's rule syntax:
||tracker.example.net^
@@||cdn.example.com^
The first line blocks tracker.example.net and all its subdomains. The second, starting with @@, allows cdn.example.com even if a blocklist contains it.
To return your own address for a name, for example an internal service, use Filters > DNS rewrites instead of a filtering rule: enter the domain and the IP address it should resolve to.
When something stops working, open Query Log, find the domain and check which list or rule blocked it. You can unblock it from there with one click.
Step 6 - Getting a TLS certificate
DNS-over-HTTPS and DNS-over-TLS need a certificate for dns.example.com. Install Certbot and open port 80 for the HTTP challenge:
sudo apt install certbot
sudo ufw allow 80/tcp
Request the certificate with Certbot's standalone web server:
sudo certbot certonly --standalone -d dns.example.com
Successfully received certificate.
Certificate is saved at: /etc/letsencrypt/live/dns.example.com/fullchain.pem
Key is saved at: /etc/letsencrypt/live/dns.example.com/privkey.pem
AdGuard Home reads the certificate files only when it starts, so create a deploy hook that restarts it after each renewal:
sudo nano /etc/letsencrypt/renewal-hooks/deploy/adguardhome.sh
#!/usr/bin/env bash
set -euo pipefail
systemctl restart AdGuardHome
Make it executable and test the renewal process:
sudo chmod +x /etc/letsencrypt/renewal-hooks/deploy/adguardhome.sh
sudo certbot renew --dry-run
Step 7 - Enabling DNS-over-HTTPS and DNS-over-TLS
Open the ports for encrypted DNS. Port 443 carries DNS-over-HTTPS and the admin interface, 853/tcp carries DNS-over-TLS and 853/udp DNS-over-QUIC:
sudo ufw allow 443/tcp
sudo ufw allow 853/tcp
sudo ufw allow 853/udp
In AdGuard Home, open Settings > Encryption settings and fill in:
- Enable encryption: checked.
- Server name:
dns.example.com. - HTTPS port:
443. DNS-over-TLS port:853. DNS-over-QUIC port:853. - Certificates: choose Set a certificates file path and enter
/etc/letsencrypt/live/dns.example.com/fullchain.pem. - Private key: choose Set a private key file and enter
/etc/letsencrypt/live/dns.example.com/privkey.pem.
Click Save configuration. AdGuard Home validates the certificate and shows the resulting endpoints. From now on you can open the admin interface at https://dns.example.com without the SSH tunnel.
Test DNS-over-HTTPS from any computer. curl resolves example.com through your server and then fetches the page:
curl --doh-url https://dns.example.com/dns-query -sI https://example.com | head -n 1
HTTP/2 200
Test DNS-over-TLS with kdig, from the knot-dnsutils package:
sudo apt install knot-dnsutils
kdig @dns.example.com +tls-ca +tls-hostname=dns.example.com cubepath.com
The output starts with a ;; TLS session line and ends with the answer section. The queries also appear in AdGuard Home's Query Log.
Step 8 - Connecting your devices
Use these addresses on your clients:
| Protocol | Address | Where to use it |
|---|---|---|
| DNS-over-HTTPS | https://dns.example.com/dns-query | Firefox, Chrome, Windows 11, iOS/macOS profiles |
| DNS-over-TLS | dns.example.com | Android "Private DNS", systemd-resolved |
| Plain DNS | your_server_ip | Routers, only from networks you allow |
To tell devices apart, and to apply different settings to each one, add a client ID to the address. For example, https://dns.example.com/dns-query/laptop or laptop.dns.example.com for DNS-over-TLS; the latter requires a wildcard certificate. Then create a matching client under Settings > Client settings, where you can enable parental control, safe search or blocked services per device.
If you want plain DNS on port 53 for your home router, allow only your home IP:
sudo ufw allow from your_client_ip to any port 53 proto udp
sudo ufw allow from your_client_ip to any port 53 proto tcp
Troubleshooting
AdGuardHome fails to start with bind: address already in use. Another service uses port 53, 443 or 3000. Find it with sudo ss -lntup | grep -E ':(53|443|853|3000) '. On Ubuntu this is usually the systemd-resolved stub, so repeat Step 1.
The service does not start after editing the YAML by hand. Always stop the service before editing /opt/AdGuardHome/AdGuardHome.yaml, because it overwrites the file on shutdown. Validate your changes with sudo /opt/AdGuardHome/AdGuardHome --check-config -c /opt/AdGuardHome/AdGuardHome.yaml and read the log with sudo journalctl -u AdGuardHome -n 50 --no-pager.
Encryption settings reject the certificate. Make sure the server name matches the certificate and that you used the paths under /etc/letsencrypt/live/, not archive/.
Certificate renewal fails. The standalone challenge needs port 80 open and free. Check with sudo certbot renew --dry-run.
Conclusion
AdGuard Home is now blocking ads and trackers on Ubuntu 24.04 and serving encrypted DNS-over-HTTPS and DNS-over-TLS with an automatically renewed certificate, so your devices are protected on any network. Next, you can create per-device clients with their own filtering rules, point AdGuard Home to a local Unbound resolver as its upstream to avoid public resolvers entirely, or add a second server for redundancy.
