Homelab Part 3 — Internal DNS with AdGuard Home
Installing AdGuard Home as the internal DNS server for the homelab — so every service gets a clean hostname instead of an IP address, plus network-wide ad blocking as a bonus.
Why I Need Internal DNS
Right now, to access a service running on my K3s VM, I’d type something like http://192.168.1.51:30080. That’s ugly, hard to remember, and breaks the moment I change the IP.
What I want is: http://jellyfin.home.lab — from any device on my network.
To make that work, I need a DNS server that knows about my internal hostnames. My router’s built-in DNS only knows about the internet — it has no idea what jellyfin.home.lab means. I need my own DNS server that I control.
AdGuard Home does this and blocks ads across the entire network as a side effect.
Installing AdGuard Home
I SSH into the DNS VM (192.168.1.50):
1
ssh homelab@192.168.1.50
Download and run the AdGuard Home installer:
1
curl -s -S -L https://raw.githubusercontent.com/AdguardTeam/AdGuardHome/master/scripts/install.sh | sh -s -- -v
The installer:
- Downloads the AdGuard Home binary
- Installs it as a systemd service
- Starts it automatically
[SCREENSHOT]— Terminal showing AdGuard Home installation completing with “AdGuard Home is now installed and running”
Initial Setup via Web UI
AdGuard Home has a web interface. After installation, I open a browser on my laptop and go to:
1
http://192.168.1.50:3000
The setup wizard runs:
- Admin interface port: keep
3000(or change to80if you want) - DNS server port: keep
53 - Username and password: set something secure
- DNS upstream servers: I use Cloudflare (
1.1.1.1) and Google (8.8.8.8)
Click Next → Next → Open Dashboard.
[SCREENSHOT]— AdGuard Home web dashboard showing query stats and DNS activity
Configuring Upstream DNS
In Settings → DNS settings → Upstream DNS servers, I configure which servers AdGuard uses for queries it can’t answer itself:
1
2
https://dns.cloudflare.com/dns-query
https://dns.google/dns-query
Using DNS-over-HTTPS (DoH) means my DNS queries are encrypted — my ISP can’t see what I’m looking up.
Bootstrap DNS servers (used to resolve the DoH hostnames themselves):
1
2
1.1.1.1
8.8.8.8
[SCREENSHOT]— AdGuard DNS settings page showing upstream servers configured with DoH URLs
Adding Internal DNS Records
This is the key step — telling AdGuard Home about my homelab hostnames.
Go to Filters → DNS rewrites → Add DNS rewrite:
| Domain | Answer |
|---|---|
jellyfin.home.lab | 192.168.1.200 |
nextcloud.home.lab | 192.168.1.200 |
k3s.home.lab | 192.168.1.51 |
adguard.home.lab | 192.168.1.50 |
192.168.1.200 is the IP MetalLB will assign to my Nginx Ingress — all services share one IP, with the hostname determining which service they reach. I’ll configure MetalLB in Part 5.
[SCREENSHOT]— AdGuard DNS rewrites page showing all four entries added
Pointing My Devices to AdGuard
Now I need my devices to use AdGuard Home (192.168.1.50) as their DNS server instead of the router’s built-in DNS.
Option A — Router Level (Recommended)
Best option — every device on the network automatically uses AdGuard without any per-device config.
In my router admin panel:
- Find the DHCP settings
- Change the DNS server (or “Primary DNS”) from
192.168.1.1(router) to192.168.1.50(AdGuard VM)
After saving, any device that reconnects to WiFi or renews its DHCP lease will use AdGuard.
[SCREENSHOT]— Router admin panel showing DHCP DNS field changed to 192.168.1.50
Option B — Per Device (Fallback)
If I can’t change the router (ISP-locked), I set DNS manually per device:
Windows:
- Network adapter settings → IPv4 → DNS:
192.168.1.50
iPhone/iPad:
- Settings → WiFi → (i) next to network → Configure DNS → Manual →
192.168.1.50
Android:
- Settings → WiFi → long press network → Modify → Advanced → DNS:
192.168.1.50
Testing DNS Resolution
From my Windows laptop, I test that AdGuard is working:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
# Flush DNS cache first
ipconfig /flushdns
# Test internal hostname resolution
nslookup jellyfin.home.lab 192.168.1.50
# Should return: 192.168.1.200
# Test external resolution still works
nslookup google.com 192.168.1.50
# Should return Google's IPs
# Test ad blocking
nslookup doubleclick.net 192.168.1.50
# Should return 0.0.0.0 (blocked)
[SCREENSHOT]— PowerShell showing nslookup results — internal hostname resolving to 192.168.1.200, external resolving correctly
AdGuard Home — Useful Settings to Enable
Blocklists
Filters → DNS blocklists → Add blocklist
I add these:
- AdGuard DNS filter (built-in)
- EasyList
- Steven Black’s Unified Hosts
[SCREENSHOT]— AdGuard blocklists page showing enabled filter lists and total blocked domains count
Safe Browsing and Parental Controls
Settings → General settings:
- Enable Safe Browsing — blocks malicious domains
- Leave parental controls off (my network, my rules)
Query Log
Query Log in the top menu shows every DNS query from every device in real time. Useful for debugging and also eye-opening — you see exactly how many tracking requests every device makes.
[SCREENSHOT]— AdGuard query log showing device IPs, queried domains, and blocked/allowed status
Making AdGuard Survive Reboots
AdGuard Home is installed as a systemd service, so it starts automatically:
1
2
sudo systemctl status AdGuardHome
sudo systemctl enable AdGuardHome # should already be enabled
The VM itself auto-starts in VMware if I set it: VMware → VM → Settings → Options → Advanced → Power on this virtual machine after the host powers on
[SCREENSHOT]— systemctl status AdGuardHome showing active (running)
Where I Am Now
At the end of Part 3 I have:
- ✅ AdGuard Home running on
192.168.1.50 - ✅ All my home devices using it as DNS
- ✅ Internal hostnames (
jellyfin.home.lab,nextcloud.home.lab) resolving to192.168.1.200 - ✅ Ad blocking active network-wide
- ✅ Encrypted DNS queries (DoH to Cloudflare and Google)
The DNS is ready. Next: set up the K3s Kubernetes cluster on the main VM.
