Introduction
Every device on your network is quietly making DNS requests all day long, and a lot of those requests are for things you'd rather not load: ad networks, tracking pixels, telemetry pings from apps you didn't know were phoning home. You can install an ad blocker in your browser, but that only covers the browser. Your smart TV, your phone's apps, your game console, none of that gets touched.
AdGuard Home fixes that at the network level. It's a DNS server that filters out junk domains before they ever load, and it protects every device on your network at once, no browser extensions required. Running it in an LXC container on Proxmox VE means it barely touches your host's resources and stays completely separate from everything else you're running.
If you've read about Pi-hole before, AdGuard Home solves the same basic problem but ships as a single binary with a built-in setup wizard, and it supports encrypted DNS out of the box without extra configuration. Neither one is objectively better for every situation, but AdGuard Home is worth setting up on its own merits.
What You Will Learn
- What AdGuard Home actually does and how DNS-based filtering works
- Why running it in an LXC container makes more sense than a full VM for this job
- How to create a Debian 12 container for it on Proxmox VE
- How to install AdGuard Home and get through the setup wizard
- How to give the container a static IP and point your network at it
- What to do when the install script fails or DNS queries aren't reaching it
What Is This Feature?
AdGuard Home is an open-source DNS server with built-in filtering. When a device on your network wants to load ads.example-tracker.com, its DNS request goes to AdGuard Home first. If that domain is on one of AdGuard Home's blocklists, it returns nothing (or a blank response), and the ad or tracker never loads. If the domain is fine, it forwards the request upstream and returns the real answer, the same as any other DNS server would.
This runs inside an LXC container, which is Proxmox VE's built-in way of running lightweight Linux environments. Unlike a virtual machine, an LXC container shares the host's kernel instead of running its own, so it starts in a couple of seconds and uses a fraction of the RAM and disk a VM would need for the same job. For something like AdGuard Home, which is a small background service and nothing more, an LXC container is a much better fit than spinning up a full VM.
AdGuard Home also does something Pi-hole doesn't handle out of the box: encrypted DNS. It can forward your queries upstream over DNS-over-HTTPS or DNS-over-TLS, so your ISP (or anyone else watching your network traffic) can't see a plain-text list of every domain you're resolving.
Why Would You Use It?
The honest answer for most homelab users is that browser-based ad blockers already handle 90% of the annoyance on a laptop or desktop. AdGuard Home earns its keep on everything else: the ads inside your phone's free apps, the tracking beacons on your smart TV, the telemetry your smart speaker sends out every few minutes. None of those respect a browser extension, because there is no browser.
There's also a speed benefit that's easy to underestimate. Once a domain is blocked at the DNS level, the request never leaves your network. Pages that are loaded with third-party trackers and ad scripts often feel noticeably snappier once those requests just fail instantly instead of timing out.
And because it's running in its own container, you can experiment freely. Break the config, try aggressive blocklists that end up blocking something you actually needed, roll back with a snapshot, no risk to anything else on your Proxmox host.
Prerequisites
- A working Proxmox VE 8.x or 9.x install with access to the web interface
- The Debian 12 (bookworm) container template, or the ability to download it through Proxmox
- A free IP address on your LAN to assign to the container
- Admin access to your router (or DHCP server) so you can point clients at the new DNS server
- About 15 minutes, most of which is downloading the template and waiting on apt
Step-by-Step Tutorial
Start by making sure the Debian 12 template is available. In the Proxmox web interface, click your node, then local storage, then CT Templates, then Templates. If you'd rather use the shell, this does the same thing:
pveam update
pveam available | grep debian-12
pveam download local debian-12-standard_12.7-1_amd64.tar.zst
The exact filename changes as Proxmox updates the template, so check the output of the second command if the third one fails with a "not found" error.
Now create the container. Open a shell on your Proxmox host (or use the Create CT button in the web UI, which does the same thing with prompts) and run:
pct create 201 local:vztmpl/debian-12-standard_12.7-1_amd64.tar.zst \
--hostname adguard \
--cores 1 \
--memory 512 \
--swap 512 \
--rootfs local-lvm:4 \
--net0 name=eth0,bridge=vmbr0,ip=dhcp \
--unprivileged 1 \
--features nesting=1
A few notes on those numbers before you copy-paste them. 512 MB of RAM and one core is genuinely enough for AdGuard Home under normal home use; it's a lightweight Go binary, not a database server. A 4 GB disk is plenty for the OS plus AdGuard Home's logs and blocklist cache, though bump it to 8 GB if you plan to keep detailed query logs for a long time. The container ID (201 here) just needs to be unused on your system, pick any free number.
Start the container and log in:
pct start 201
pct enter 201
Update the base system before installing anything on top of it:
apt update && apt full-upgrade -y
Now run AdGuard Home's official install script:
curl -sSL https://raw.githubusercontent.com/AdguardTeam/AdGuardHome/master/scripts/install.sh | sh -s -- -v
This downloads the latest AdGuard Home release, unpacks it to /opt/AdGuardHome, and registers it as a systemd service that starts automatically. When it finishes, it prints a URL for the setup wizard, something like http://192.168.1.50:3000.
Open that address in a browser on your regular network (not inside the container). The wizard walks you through:
- Choosing which network interfaces the admin panel listens on, and which port. Port 80 is the default suggestion; I'd change it to something like 3080 so it doesn't collide with anything else you might run on this container later.
- Choosing the DNS listening interface and port. Leave this on port 53, that's the standard DNS port and changing it means every client needs a non-standard port configured, which most devices don't support anyway.
- Setting an admin username and password for the dashboard.
Once the wizard finishes, you're dropped into the AdGuard Home dashboard, already filtering with a solid default blocklist active.
Before you point your whole network at it, give the container a static IP so it doesn't change on you after a reboot. Back on the Proxmox host:
pct set 201 --net0 name=eth0,bridge=vmbr0,ip=192.168.1.53/24,gw=192.168.1.1
pct reboot 201
Swap in your own subnet and gateway. Finally, go into your router's DHCP or DNS settings and set the primary DNS server to the container's new IP address. Most routers have this under a section called DHCP Server or LAN Setup. Give it a minute, then check a device that's renewed its lease, it should now be sending its DNS queries through AdGuard Home.
Commands Explained
- pveam update refreshes Proxmox's local list of available container templates from the online repository.
- pveam download pulls a specific template down to local storage so pct create can use it.
- pct create builds a new LXC container from a template, with flags controlling its ID, resources, and network setup.
- --unprivileged 1 runs the container with reduced permissions relative to the host, which is the safer default for anything that doesn't specifically need root-level host access.
- pct start and pct enter boot the container and drop you into a shell inside it, similar to SSH but without needing a network connection to work.
- pct set changes a container's configuration, in this case its network settings, without needing to recreate it.
- curl -sSL ... | sh -s -- -v downloads AdGuard Home's install script and runs it with verbose output, so you can see exactly what it's doing as it installs the binary and sets up the systemd service.
Common Errors
"bind: address already in use" when AdGuard Home starts. Something else on the container is already listening on port 53 or port 80. On a fresh Debian 12 template this is almost always systemd-resolved, which ships enabled by default and binds to port 53 for its own local resolver. Check with:
ss -tulnp | grep :53
If systemd-resolved shows up there, disable its DNS stub listener (covered in Troubleshooting below).
Template not found during pct create. The filename in the Proxmox package repo changes with every point release. Run pveam available | grep debian-12 and copy the exact filename it returns instead of guessing.
Setup wizard never loads at :3000. Usually a firewall issue. If you've enabled the Proxmox firewall on this container, add a rule allowing TCP port 3000 inbound from your LAN, or temporarily disable the container firewall while you finish setup.
Devices ignore the new DNS server. Some devices, phones especially, hardcode a public DNS server (like 8.8.8.8) instead of using whatever the router hands out over DHCP. You'll need to either change that setting on the device itself or block outbound DNS to everything except your AdGuard Home container at the router or firewall level.
Troubleshooting
If port 53 is stuck in use by systemd-resolved, disable its stub listener rather than trying to stop the whole service (a lot of Debian tooling expects it to be running):
mkdir -p /etc/systemd/resolved.conf.d
printf "[Resolve]\nDNSStubListener=no\n" > /etc/systemd/resolved.conf.d/no-stub.conf
systemctl restart systemd-resolved
Then restart AdGuard Home and confirm it's holding port 53:
systemctl restart AdGuardHome
systemctl status AdGuardHome
ss -tulnp | grep :53
To confirm filtering is actually working from a client machine, query a known ad domain directly against the container's IP:
nslookup doubleclick.net 192.168.1.53
A blocked domain should come back with 0.0.0.0 or no answer at all, instead of a real IP address. If it resolves normally, double check the client is actually using the container as its DNS server, run ipconfig /all on Windows or cat /etc/resolv.conf on Linux/Mac to see what DNS server it's really pointed at.
If the whole container seems unreachable after the static IP change, log in through the Proxmox console (not SSH) and double check the gateway and subnet mask match your actual network. A typo here is the single most common reason a container "disappears" right after a network change.
Best Practices
- Take a snapshot of the container right after the initial setup wizard finishes, so a bad blocklist or misconfiguration is one click away from undone.
- Set a second DNS server in your router's config, either your ISP's resolver or a public one like 1.1.1.1, as a fallback if the container ever goes down. Otherwise a Proxmox host reboot means nobody on your network can resolve anything until it's back up.
- Turn on DNS-over-HTTPS for upstream queries in AdGuard Home's settings. It's a couple of clicks and keeps your DNS traffic private from your ISP.
- Don't go overboard with blocklists on day one. Start with the defaults, use the site for a week, and only add more aggressive lists once you're confident nothing important is getting blocked.
- Back up the container regularly with vzdump, same as you would any other LXC container. Configuration and query history both live inside it.
Frequently Asked Questions
Can I run AdGuard Home and Pi-hole on the same network?
Yes, but only one should actually be handling DNS for your devices at a time. Running both is mostly useful if you want to test one against the other before switching over.
Will this slow down my internet?
No, if anything it usually feels faster, since blocked requests fail instantly instead of waiting on a real server that never responds. The container adds a few milliseconds of lookup time at most.
Does my ISP-provided router already do this?
A handful of routers have basic ad-blocking built in, but it's usually a fixed, unchangeable list with no dashboard, no stats, and no encrypted DNS option. AdGuard Home gives you actual control over what's blocked and why.
What happens if the container crashes?
Every device that was using it as their DNS server loses name resolution until it's back up, which is why setting a fallback DNS server on your router matters. Consider setting the container to autostart with the Proxmox host, so a host reboot brings it back automatically.
Can devices bypass it?
Any device that hardcodes its own DNS server (public DNS apps, some smart TVs, certain streaming boxes) will bypass AdGuard Home unless you block outbound port 53 to everything except the container at your router or firewall.
Conclusion
AdGuard Home in an LXC container gives you network-wide filtering for less resource overhead than almost anything else you could run for the same job, and the setup wizard means you're not fighting with a bare config file to get there. The whole process, template download, container creation, install script, and router change, realistically takes about fifteen minutes.
Once it's running, the payoff is mostly invisible: fewer ads loading on devices that never had a blocker to begin with, and a dashboard that shows you exactly what your network has been quietly trying to load all along.