Self-Host AdGuard Home with pfSense on Proxmox LXC

– min read

I wanted full control over DNS on my home lab. I have been running pfSense as my gateway for a while and stumbled upon AdGuard Home — a self-hosted DNS server that blocks ads, trackers, and malware network-wide. Here is how I set it up on a Proxmox LXC container and locked everything through pfSense.

GitHub: github.com/AdguardTeam/AdGuardHome
Official Site: adguard.com/adguard-home.html


What Is AdGuard Home

AdGuard Home is a network-wide DNS filtering server written in Go. It sits between your devices and the internet, intercepting every DNS query and blocking the bad ones before they even reach your browser. Think Pi-hole but with a proper web UI, DNS-over-HTTPS/QUIC support, per-client stats, and built-in DHCP server. It also supports custom blocklists, DNS rewrites, and upstream DNS encryption — all from a single lightweight binary.


My Setup

Here is the layout I run:

ComponentIP AddressRole
pfSense10.13.37.1Gateway, DHCP, firewall
AdGuard Home10.13.37.11DNS filtering (LXC on Proxmox)
Proxmox VE10.13.37.15Hypervisor hosting the LXC


Installation on Proxmox LXC

I created a lightweight Ubuntu 24.04 LXC container on Proxmox. The minimum spec is tiny — 512 MB RAM and one CPU core are enough. Once the container was up, I had two ways to install AdGuard Home: the official script or Docker. I went with the standalone script because it keeps things simple.

First, SSH into the container and run the official installer:

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

The script downloads the latest release for your architecture and places the binary at /opt/AdGuardHome/AdGuardHome. It also creates a systemd service so AdGuard Home starts automatically on boot.

Alternatively, if you prefer Docker, run it with host networking to avoid port mapping headaches:

docker run -d \
  --name adguardhome \
  --restart unless-stopped \
  --network host \
  -v /opt/adguardhome/work:/opt/adguardhome/work \
  -v /opt/adguardhome/conf:/opt/adguardhome/conf \
  adguard/adguardhome:latest

I used the standalone method. After installation, start the service and enable it:

systemctl enable --now AdGuardHome
systemctl status AdGuardHome


Initial Web UI Setup

Point your browser to http://10.13.37.11:3000 (or whatever IP your LXC has). The setup wizard walks you through:

  1. Admin interface — leave the default 0.0.0.0:3000 (or switch to port 80 after pfSense is configured so you just hit the IP).
  2. DNS server — bind to 0.0.0.0:53 on all interfaces (the main DNS listener).
  3. Upstream DNS — I use Quad9 (9.9.9.9) and Cloudflare (1.1.1.1) with DNS-over-TLS for encryption. In AdGuard, tick “Use Private” for upstream servers and set tls://9.9.9.9 and tls://1.1.1.1.
  4. Admin password — set a strong one.

If you plan to run AdGuard on port 53, make sure no other service (like systemd-resolved) is already bound to it:

ss -tulpn | grep ':53 '
lsof -i :53

If something else is listening, stop it. On Ubuntu, disable systemd-resolved with:

systemctl disable --now systemd-resolved
rm -f /etc/resolv.conf
echo 'nameserver 9.9.9.9' > /etc/resolv.conf


Locking DHCP to AdGuard Home in pfSense

This is the critical step. Every device on your LAN should use AdGuard Home as its DNS server. pfSense hands out DNS settings via DHCP, so we need to tell it to give clients the AdGuard IP.

In the pfSense web UI:

  1. Go to Services > DHCP Server.
  2. Select your LAN interface tab.
  3. Scroll to DNS Servers.
  4. Set DNS Server 1 to 10.13.37.11 (your AdGuard IP).
  5. Set DNS Server 2 blank (or the AdGuard IP again for redundancy).
  6. Uncheck “DNS Gateway” — we want clients to talk to AdGuard directly.
  7. Click Save and then Apply Changes.

Also, head to Services > DNS Resolver (Unbound) and enable DHCP Registration and Static DHCP. This lets AdGuard resolve local hostnames from pfSense DHCP leases. Then set the DNS Resolver to listen only on localhost (127.0.0.1) — not the LAN interface — because AdGuard handles LAN DNS now.

# On pfSense: Services > DNS Resolver
# Enable: DHCP Registration
# Enable: Static DHCP
# Listen Port: 53
# Network Interfaces: Localhost (127.0.0.1) only


Redirect All DNS Traffic (Port 53 Enforcement)

Even with DHCP handing out the correct DNS, rogue devices or hardcoded DNS apps can bypass it. To enforce DNS through AdGuard, I created a pfSense NAT redirect rule that intercepts every outbound DNS query on port 53.

Go to Firewall > NAT > Port Forward and add a rule:

# Port Forward Rule
# ────────────────────────────────────────
# Interface:   LAN
# Protocol:    TCP/UDP
# Source:      LAN Net (invert match)
# Source Port: *
# Dest. addr:  !10.13.37.11  (NOT AdGuard IP)
# Dest. port:  53
# Redirect IP: 10.13.37.11
# Redirect port: 53
# Description: Force all DNS through AdGuard Home

In the rule, check Source: Invert match on the AdGuard IP so its own queries still reach upstream. The rule says: “If any device on the LAN tries to send a DNS query to anything other than 10.13.37.11:53, redirect it to 10.13.37.11:53.” This is the kill switch — clients that ignore DHCP DNS settings get silently redirected anyway.

For pfSense official documentation on DNS redirect, check out the Netgate DNS Redirect Guide.


Custom Blocklists

AdGuard Home comes with a decent default filter list, but the real power is adding third-party blocklists. I use HaGeZi blocklists (by GitHub user hagezi) — widely considered the gold standard for DNS-level blocking. They are comprehensive, well-maintained, and have tiers from Light to Ultimate.

In the AdGuard Home web UI (Filters > DNS blocklists > Add blocklist > Add a custom list), I add these:

# HaGeZi Pro++ Blocklist (recommended balance)
# Blocks: ads, trackers, malware, phishing, scams
https://raw.githubusercontent.com/hagezi/dns-blocklists/main/adblock/pro++.txt

# HaGeZi Threat Intelligence Feeds (TIF)
# Blocks: known malicious IPs, C2 domains
https://raw.githubusercontent.com/hagezi/dns-blocklists/main/adblock/tif.txt

# HaGeZi Badware Hoster
# Blocks: domains hosting malware
https://raw.githubusercontent.com/hagezi/dns-blocklists/main/adblock/badware-hoster.txt

# OISD Big (full)
https://big.oisd.nl/domainswild

# AdGuard DNS filter
https://adguardteam.github.io/HostlistsRegistry/assets/filter_1.txt

HaGeZi has several tiers. Here is a quick breakdown:

ListWhat It BlocksBreakage Risk
LightAds + trackersLow
NormalLight + malware + scamsLow
ProNormal + crypto + fake newsLow-Medium
Pro++Pro + aggressive anti-adblockMedium
UltimateEverything — nuclear optionHigh

I run Pro++ and TIF. If something breaks (rare), I check the query log in AdGuard, find the blocked domain, and add an allowlist rule. The AdGuard UI makes this painless — just click the query and hit “Unblock.”

HaGeZi GitHub: github.com/hagezi/dns-blocklists


Verification

Once everything is running, verify DNS is going through AdGuard. On any machine on your LAN:

# Check your DNS server
nslookup google.com
# Should show 'Server: 10.13.37.11'

# Verify blocking
dig doubleclick.com @10.13.37.11
# Should return 0.0.0.0 or NXDOMAIN if blocked

# Check upstream via AdGuard
dig google.com @10.13.37.11 +short
# Should resolve normally

On the client side, check what DNS your machine picked up from DHCP:

# Linux / macOS
scutil --dns | grep 'nameserver'

# Windows
ipconfig /all | findstr DNS

# Check if DNS redirect is active (use a public DNS server)
nslookup google.com 8.8.8.8
# If this fails/times out → redirect is working


Bonus: Let AdGuard Handle DHCP Too

If you want to go all-in, you can disable pfSense DHCP and let AdGuard Home run the DHCP server. This gives you per-client DNS query stats in the AdGuard dashboard and more granular control. You can see which device is making how many queries and hitting what blocklists — all with device hostnames instead of raw IPs.

To do this, in AdGuard go to Settings > DHCP settings, enable the DHCP server, set the gateway to 10.13.37.1 (pfSense), and the subnet range that matches your LAN. Then disable the DHCP server in pfSense (Services > DHCP Server, uncheck “Enable DHCP server”).

I personally keep DHCP on pfSense and just point DNS to AdGuard — it is less disruptive if I need to take the LXC down for maintenance.


AdGuard Home has been rock solid in my lab. The query log alone is worth it — I caught several IoT devices phoning home to tracking domains I did not even know about. Combined with pfSense firewall redirect and HaGeZi blocklists, I get network-wide ad blocking with zero configuration on individual devices. If you are already running pfSense, adding AdGuard Home is the next best step for your network hygiene.

Mohamad ZulfahmyCybersecurity · OffSec · Entrepreneur
About me ↗
ON THIS PAGE
On this page