Troubleshooting
The failures that actually happen, in the order they actually happen.
The failures that actually happen, in roughly the order they happen. Each one starts with how to tell it apart from the others, because most of these look identical from the dashboard.
Nothing is being logged at all#
The dashboard is empty and the dot is green#
Ingest is working and there is nothing to ingest. Open AdGuard Home’s own dashboard: if its query count is also flat, nothing on your network is using it as a resolver.
Fix it in your router’s DHCP settings: set the primary DNS server to this box, and remove any secondary. Devices already on the network keep their old lease until it renews, so test by rebooting one, or check from the box itself with dig @127.0.0.1 example.com.
Some devices appear and others never do#
Those devices are not using this resolver. Three common reasons: a hardcoded DNS server (many smart TVs and consoles ship with 8.8.8.8 baked in), a VPN on the device, or DNS over HTTPS in the browser.
The Anomalies page detects the third case by looking for lookups of known DoH endpoints. For the first, block outbound port 53 at the router to anything except this box, which forces them back.
Port 53#
AdGuard Home will not start: address already in use#
Something else holds , almost always . Confirm:
sudo ss -lntup | grep ':53'The fix is to stop its stub listener while leaving name resolution working:
sudo mkdir -p /etc/systemd/resolved.conf.d
printf '[Resolve]\nDNSStubListener=no\n' | sudo tee /etc/systemd/resolved.conf.d/elele.conf
sudo ln -sf /run/systemd/resolve/resolv.conf /etc/resolv.conf
sudo systemctl restart systemd-resolvedThe installer offers to do exactly this. It does not disable systemd-resolved; it stops it listening on 53 and points the system at its real resolver file instead.
Pi-hole owns port 53 already#
Nothing here binds it, so the usual fight was settled when you installed Pi-hole. If Pi-hole itself stops answering on , that is a Pi-hole problem and this dashboard will simply report growing lag while it lasts.
Worth knowing which one is actually listening when something is odd:
sudo ss -lntup | grep ':53'Credentials and connectivity#
Health says the resolver is unreachable#
Check the three things in that order, because they fail differently.
# 1. Is it up at all?
curl -sv http://192.168.1.10:3000/control/status
# 2. Do the credentials work?
curl -s -u admin:password http://192.168.1.10:3000/control/status
# 3. Can the container reach it?
sudo docker exec elele-dns wget -qO- http://192.168.1.10:3000/control/statusIf 1 and 2 work from the host but 3 fails, it is Docker networking: 127.0.0.1 inside a container is the container, not the host. Use the host’s LAN address in ADGUARD_URL, not localhost.
401 Unauthorized, and the password is definitely right#
AdGuard Home rate-limits failed logins. After several bad attempts it will reject correct ones for a while too. Wait a minute, then retry. If it persists, reset the password with AdGuardHome --update-password or by editing the bcrypt hash in AdGuardHome.yaml.
Health says Pi-hole is unreachable#
Check the three things in that order, because they fail differently. Authentication on v6 is a session rather than a header, so step 2 is a POST that hands back a session id:
# 1. Is the API up?
curl -sv http://192.168.1.10/api/info/version
# 2. Does the password work? Returns a session id.
curl -s -X POST http://192.168.1.10/api/auth \
-H 'Content-Type: application/json' \
-d '{"password":"your-app-password"}'
# 3. Can the container reach it?
sudo docker exec elele-dns wget -qO- http://192.168.1.10/api/info/versionIf 1 and 2 work from the host but 3 fails, it is Docker networking: 127.0.0.1 inside a container is the container, not the host. Use the host’s LAN address in PIHOLE_URL, not localhost.
A 404 on /api/info/version almost always means v5. There is no fallback: v6 replaced those endpoints outright, and only the new ones are implemented.
401 Unauthorized, and the password is definitely right#
Pi-hole has a small fixed number of session seats, and a 401 here usually means they are all taken rather than that the password is wrong — the client already retried with a fresh login before surfacing the error. Log out idle sessions under Settings, or generate an application password so this dashboard holds a seat of its own.
A password with 2FA attached will also fail. Use an application password instead, which bypasses the TOTP prompt by design and can be revoked without changing the password you type.
Ingest#
The lag figure keeps growing#
Ingest is falling behind the rate queries are arriving. Read the real numbers first:
curl -s http://127.0.0.1:3000/api/ingest/status | jqThen look at progress.lagMs against the poll interval. Sustained lag on a household network usually means the box is IO-starved: a worn SD card is the usual culprit, and moving the data directory to an SSD fixes it outright. Lowering INGEST_POLL_INTERVAL_MS makes this worse, not better.
Negative lag#
AdGuard Home’s clock is ahead of this host’s. It is reported rather than clamped to zero, because skew large enough to see here also shifts which hour a query gets rolled into. Fix the clock: timedatectl on both.
Backfill never finishes#
walks back until the resolver stops returning older pages. If its buffer is very large and the box is slow, this can take a while, and it deliberately runs a bounded number of pages per pass so it never starves the live poll. Watch progress.backfillComplete; if it is still false after an hour, check the log for pagination errors.
Data looks wrong#
Every device is called by its IP address#
Names come from three places, in order: what you set in this dashboard, what AdGuard Home knows, and the DHCP lease hostname. If AdGuard Home is not running DHCP and you have not named anything, addresses are all there is. Name them on the Devices page; it writes back to AdGuard Home too, so the two stay in step.
Every device is called by its IP address#
On Pi-hole the names come from FTL’s own reverse lookup, attached to each query. If they are missing there, the devices have no reverse DNS on your network — giving them static DHCP reservations with hostnames on your router fixes it at the source, for every tool rather than just this one.
You can still name them on the Devices page. Unlike the AdGuard path it does not write back, so the name lives here and Pi-hole carries on showing what it resolved.
No companies are attributed#
The companiesdb dataset has not loaded. Check curl -s localhost:3000/api/ingest/status | jq .datasets, then run npm run datasets:fetch (or recreate the container, which ships them). Attribution is resolved once when a domain is first seen, so already-stored domains stay unattributed until they are seen again.
The map is all country blobs and no cities#
The optional GeoLite2 city files are not installed. The map falls back to country centroids, which is why everything lands in the middle of a country. They are operator-supplied because of MaxMind’s licence; see Enrichment.
Blocked queries have no destination#
Correct, and not a bug. A blocked query was answered by AdGuard Home itself, so there is no resolved address to geolocate. The map draws them as short stubs off the home marker rather than dropping them, because they are half the traffic and the interesting half.
Destinations is missing from the navigation#
Correct, and permanent rather than a configuration problem. The map is built from the IP addresses inside each DNS answer. FTL’s query API reports what kind of reply it sent — an address, a CNAME, NXDOMAIN — but never the addresses the reply contained, so there is nothing to place on a map.
The section is hidden rather than shown empty on purpose: an empty map reads as “your network went nowhere”, which is false. Country, city and ASN columns are blank on Pi-hole for the same reason. Everything not derived from answer addresses — devices, domains, companies, friction, anomalies, the explorer — is unaffected.
Devices have no hardware vendor#
Vendor labels come from a device’s MAC address, matched against the IEEE OUI registry. AdGuard Home exposes MACs through its client and DHCP APIs; the equivalent Pi-hole endpoints are not read yet, so devices are named but not labelled “Apple” or “Sonos”. Unlike the map, this one is a gap rather than an impossibility.
Getting the logs#
sudo docker compose logs -f --tail 200 # the app
sudo docker logs adguardhome --tail 200 # the resolver
sudo journalctl -u docker --since "10 min ago" # the daemonsudo docker compose logs -f --tail 200 # the app
pihole-FTL --logs # the resolver, if Pi-hole is on the host
sudo journalctl -u docker --since "10 min ago" # the daemon