Networking Azure

AdGuard Home Unbound on Ubuntu 24.04 on Azure User Guide

| Product: AdGuard Home Unbound on Ubuntu 24.04 LTS on Azure

Overview

AdGuard Home is a network wide DNS server that blocks ads, trackers and malicious domains for every device that points its DNS at it, with no client software to install on each device. This cloudimg image pairs it with Unbound, a validating, recursive, caching DNS resolver, configured as AdGuard's private upstream on the loopback address 127.0.0.1:5335. Instead of forwarding your lookups to a third party public resolver, every query is resolved directly from the DNS root servers with DNSSEC validation, so no external DNS provider sees your browsing and every answer is cryptographically verified.

Point a single device or your whole router at this VM on port 53 and its DNS lookups are filtered by AdGuard, resolved recursively by Unbound, logged and visible in a clean web dashboard. The cloudimg image installs AdGuard Home 0.107.78 as a systemd service running the DNS server on port 53 (UDP and TCP) and the built in web admin bound to the loopback address 127.0.0.1:3000 behind an nginx reverse proxy on port 80, plus Unbound as a systemd service bound to 127.0.0.1:5335. On Ubuntu 24.04 the systemd resolved stub listener is disabled during the build so AdGuard owns port 53 cleanly. All AdGuard runtime state, the configuration, query logs, statistics and filter caches, lives on a dedicated Azure data disk, and a unique admin username and password is generated on the first boot of every VM. Backed by 24/7 cloudimg support.

What is included:

  • AdGuard Home 0.107.78 managed by systemd, serving DNS on port 53 (UDP and TCP)
  • Unbound, a validating recursive resolver bound to 127.0.0.1:5335, set as AdGuard's private upstream
  • Recursive DNSSEC validated resolution directly from the DNS root servers, with no third party public resolver
  • The AdGuard web admin on port 80, fronted by nginx and bound to 127.0.0.1:3000
  • The AdGuard DNS filter enabled out of the box so ads and trackers are blocked immediately
  • A unique admin username and password generated on first boot and recorded in a root only file
  • A dedicated Azure data disk at /var/lib/adguardhome holding the config, query logs and statistics
  • The systemd resolved stub listener freed so AdGuard owns port 53 on Ubuntu 24.04
  • unbound.service, AdGuardHome.service and nginx.service as systemd units, enabled and active
  • An unauthenticated /healthz endpoint for Azure Load Balancer health probes
  • 24/7 cloudimg support

Prerequisites

An active Azure subscription, an SSH key pair, and a VNet plus subnet in the target region. Standard_B2s (2 vCPU / 4 GiB RAM) is a comfortable starting point. NSG inbound rules: allow 22/tcp from your management network for SSH, 80/tcp for the web admin, and 53/udp and 53/tcp so devices can use the server for DNS. AdGuard serves the admin over plain HTTP on port 80; for production, terminate TLS in front of it with your own domain (see Maintenance).

Step 1 - Deploy from the Azure Marketplace

Sign in to the Azure Portal, choose Create a resource, search the Marketplace for AdGuard Home Unbound by cloudimg, and select Create. On Basics pick your subscription, resource group, region and size; under Administrator account choose SSH public key and paste your key; under Inbound port rules allow SSH (22) and HTTP (80). After deployment, add inbound rules for DNS on UDP 53 and TCP 53 so your devices can query the server. Review the dedicated data disk on the Disks tab, then Review + create -> Create.

Step 2 - Deploy from the Azure CLI

az vm create \
  --resource-group <your-rg> \
  --name adguard-home-unbound \
  --image <marketplace-image-urn> \
  --size Standard_B2s \
  --admin-username azureuser \
  --ssh-key-values ~/.ssh/id_ed25519.pub \
  --vnet-name <your-vnet> --subnet <your-subnet> \
  --public-ip-sku Standard

az vm open-port --resource-group <your-rg> --name adguard-home-unbound --port 80 --priority 1010
az network nsg rule create --resource-group <your-rg> --nsg-name <your-nsg> \
  --name allow-dns-udp --priority 1020 --protocol Udp --destination-port-ranges 53 --access Allow
az network nsg rule create --resource-group <your-rg> --nsg-name <your-nsg> \
  --name allow-dns-tcp --priority 1030 --protocol Tcp --destination-port-ranges 53 --access Allow

Step 3 - Connect to your VM

ssh azureuser@<vm-public-ip>

Step 4 - Confirm the services are running

systemctl is-active unbound.service AdGuardHome.service nginx.service

All three report active. Unbound is the private recursive resolver on 127.0.0.1:5335, AdGuard Home serves DNS on port 53 (UDP and TCP) and its web admin on the loopback address 127.0.0.1:3000, and nginx fronts the admin on port 80. All AdGuard configuration, query logs and statistics live on the dedicated Azure data disk mounted at /var/lib/adguardhome.

unbound.service, AdGuardHome.service and nginx.service active, Unbound listening on 127.0.0.1:5335, the AdGuard DNS listeners on port 53, the admin on 127.0.0.1:3000, and the dedicated data disk mounted at /var/lib/adguardhome

Step 5 - Retrieve your admin login

The AdGuard admin username and password are generated uniquely on the first boot of your VM and written to a root only file:

sudo cat /root/adguardhome-credentials.txt

This file contains ADGUARD_USERNAME, ADGUARD_PASSWORD and the URL to open. Store them somewhere safe.

The AdGuard Home version and the per VM credentials file with the generated admin username, password and URL

Step 6 - Confirm recursive DNSSEC resolution through Unbound

Unbound resolves every query directly from the DNS root servers and validates DNSSEC signatures. Query it directly on 127.0.0.1:5335, then confirm that a signed domain comes back with the ad (Authenticated Data) flag set, which proves DNSSEC validation is working:

dig @127.0.0.1 -p 5335 example.com +short
dig @127.0.0.1 -p 5335 +dnssec cloudflare.com | grep -E '^;; flags'

The first command returns a normal address. The second shows flags: qr rd ra ad, and the ad flag confirms Unbound cryptographically validated the answer. AdGuard is configured to send all upstream queries to this resolver:

curl -s http://localhost/healthz

The health endpoint returns ok. AdGuard's upstream is set to 127.0.0.1:5335 out of the box, so no third party public resolver is used.

Unbound resolving example.com directly on port 5335, the DNSSEC ad flag set on a signed domain, and AdGuard's upstream DNS confirmed as the private 127.0.0.1:5335 Unbound resolver

Step 7 - Verify DNS filtering and authentication from the command line

Confirm the DNS server resolves a normal domain and blocks a known ad domain:

dig @127.0.0.1 example.com +short
dig @127.0.0.1 ad.doubleclick.net +short

example.com returns a normal address, while the ad domain returns 0.0.0.0 because the AdGuard DNS filter blocks it. AdGuard also rejects a wrong admin password and issues a session cookie for the correct one. Read the password from Step 5 first, then post it to the login endpoint. Because the command embeds your unique password, run it interactively rather than from a script, substituting the value of ADGUARD_PASSWORD for <ADGUARD_PASSWORD>:

curl -s -o /dev/null -w '%{http_code}\n' -c cookies.txt -H 'Content-Type: application/json' -X POST --data '{"name":"admin","password":"<ADGUARD_PASSWORD>"}' http://127.0.0.1/control/login; grep -o 'agh_session' cookies.txt

A correct password returns 200 and prints agh_session (the session cookie was set). A wrong password returns 403 and sets no session cookie.

Resolving example.com, the ad domain blocked with 0.0.0.0, and the admin login round trip rejecting a wrong password and accepting the per VM password with a session cookie

Step 8 - Sign in to the dashboard

Browse to http://<vm-public-ip>/. AdGuard Home shows a sign in page; enter the username and password from Step 5.

The AdGuard Home sign in page in the browser

Once signed in, the dashboard shows live query statistics: total DNS queries, how many were blocked by filters, the busiest clients and the average processing time.

The AdGuard Home dashboard showing DNS queries, the number blocked by filters, general statistics and top clients

Step 9 - Confirm the private Unbound upstream in the dashboard

Open Settings -> DNS settings. The Upstream DNS servers box shows 127.0.0.1:5335, the private Unbound resolver, so every lookup is resolved recursively from the root servers with DNSSEC validation and no third party resolver is contacted.

The AdGuard Home DNS settings page showing the upstream DNS server set to the private 127.0.0.1:5335 Unbound resolver

Step 10 - Point your devices at the server and watch the query log

On a device or your router, set the DNS server to the VM public IP. Every lookup from that device now flows through AdGuard and appears in Query Log, where you can see which domains were processed and which were blocked, per client, in real time.

The AdGuard Home query log showing resolved and blocked domains, including ad and tracker domains blocked by the AdGuard DNS filter

Step 11 - Manage blocklists

Open Filters -> DNS blocklists to review the enabled blocklists. The image ships with the AdGuard DNS filter enabled. Add more blocklists with Add blocklist, write your own rules under Custom filtering rules, and allow specific domains with an allowlist.

The AdGuard Home DNS blocklists page showing the AdGuard DNS filter enabled with its rule count

Step 12 - Confirm state lives on the dedicated disk

AdGuard's configuration, query logs and statistics are stored under /var/lib/adguardhome on the dedicated Azure data disk, so they survive OS changes and can be resized independently:

findmnt /var/lib/adguardhome

The mount is backed by a separate Azure data disk captured into the image and re-provisioned on every VM.

Maintenance

  • Admin login: the per VM credentials live in /root/adguardhome-credentials.txt. To change the password, sign in to the dashboard and use Settings, or reconfigure through the AdGuard admin.
  • Upstream resolver: AdGuard forwards to the private Unbound resolver on 127.0.0.1:5335. Unbound's configuration is at /etc/unbound/unbound.conf.d/cloudimg-adguardhome.conf; after any change run sudo systemctl restart unbound. Leave AdGuard's Settings -> DNS settings upstream pointing at 127.0.0.1:5335 to keep recursive DNSSEC validated resolution.
  • Blocklists: add and enable blocklists under Filters -> DNS blocklists; they update automatically on a schedule.
  • Storage: all AdGuard runtime state lives under /var/lib/adguardhome on the data disk; back up that volume to protect your configuration and history.
  • Services: the units are unbound.service, AdGuardHome.service and nginx.service; after any AdGuard change run sudo systemctl restart AdGuardHome.
  • TLS: the admin is served over plain HTTP on port 80; front it with TLS (for example certbot with your own domain) before production use. AdGuard Home can also serve DNS over HTTPS and DNS over TLS once you add a certificate under Settings -> Encryption settings.
  • Security patches: unattended-upgrades remains enabled so the OS continues to receive security updates automatically.

Support

cloudimg provides 24/7 expert support for this image. Contact support@cloudimg.co.uk.