Skip to content

AdGuard Home

The DNS filter itself: whether protection is on, whether its DNS server runs, what it answered and blocked, whether its filter lists still update, whether its upstream servers answer, and whether a newer version is out.

From the DumbMonit server (or its relay agent) to the device:

PortProtocolPurpose
80TCPWeb interface and API (HTTP, default)
3000TCPOnly with the web interface left on port 3000, the first-run default
443TCPOnly with the https scheme option

A broken DNS filter does not look broken. Pages keep opening, with their ads. The usual failures are quiet: protection paused “for an hour” from the phone app and never turned back on, filter lists that stopped downloading weeks ago, an upstream DNS-over-HTTPS server that no longer answers so that every lookup waits for the next one.

DumbMonit reads AdGuard Home’s REST API (/control) with HTTP basic authentication. Tested against AdGuard Home v0.107.79 (and the v0.107.78 version check).

All metrics are prefixed dumbmonit_adguard_. Query and block figures are sums over AdGuard Home’s statistics window (24 hours unless changed in Settings → General settings), not counters: they go up and down as the window slides, and are stored as they are.

MetricWhatLabels
running1 when the DNS server runs
protection_enabled1 when protection is on
protection_paused_secondstime left before a paused protection comes back on, 0 without a pause
version_infovalue 1version
dns_queriesqueries in the statistics window
blocked_filteringqueries blocked by the filter lists and custom rules
replaced_safebrowsing, replaced_parental, replaced_safesearchanswers replaced by Browsing security, Parental control, Safe search
blocked_percentshare of queries blocked (filters, Browsing security, Parental control); absent without any query
avg_processing_secondsaverage time to answer
stats_window_seconds, stats_enabledthe statistics window and whether statistics are kept (0.107.30 and later)
upstream_responses, upstream_avg_secondsanswers and average answer time per upstream in the window, as the dashboard’s Top upstreams shows them (at most 8)upstream
upstream_up1 when AdGuard Home’s own test of that upstream passes; 0 when it fails or gives no answer within 4 seconds (at most 8). The label is the upstream as AdGuard Home writes it in its statistics (https://dns10.quad9.net:443/dns-query, 192.0.2.1:53); for an upstream that stayed silent, the line as configured.upstream
filtering_enabled1 when filtering is on in Settings → General settings
filters, filters_enabledblocklists configured, and enabled
filter_rulesrules loaded from the enabled lists
filter_rules_count, filter_update_age_secondsper enabled list (at most 32)filter
filter_oldest_update_age_secondsage of the oldest update among enabled lists
filters_never_updatedenabled lists that were never downloaded
filter_update_interval_hourshow often lists are updated; 0 turns updates off
update_check_enabled0 when AdGuard Home runs with its version check off
update_available1 when the last version check announced a newer version; absent when the check is offlatest
scrape_errorssecondary calls that failed on the last check

The version check is off in the official Docker image and in most distribution packages, which update AdGuard Home themselves: there, update_available is never written and its rule stays quiet.

Upstream statistics only count answers: an upstream that stops answering leaves no trace in them. That is why DumbMonit asks AdGuard Home to test each upstream at every check, the same test as the Test upstreams button in Settings → DNS settings: one DNS query from AdGuard Home to that upstream. A dead upstream would keep AdGuard Home waiting twice its upstream timeout (20 seconds by default); DumbMonit stops waiting after 4 seconds and reports it down. Untick the Test upstream servers option to turn this off.

The built-in rules that apply: AdGuard Home protection off, AdGuard Home DNS not running, AdGuard Home upstream failing, AdGuard Home filter lists stale, AdGuard Home update available, plus Monitor unreachable.

The panel above the charts reads what the probe stored; opening the page never connects to AdGuard Home. It says whether protection and the DNS server are on (and when a pause ends), then the queries, blocks and answer time over the statistics window, the upstream servers with their test result and answer time, and the filter lists with their rules and last update.

  1. Make a bcrypt hash of a long random password (htpasswd comes with apache2-utils or httpd-tools).

    htpasswd -B -C 10 -n -b dumbmonit 'LONG-RANDOM-PASSWORD'
  2. Stop AdGuard Home, add this line under users: in AdGuardHome.yaml with HASH replaced by the printed hash, then start it again.

    - { name: dumbmonit, password: "HASH" }
  3. In DumbMonit, enter the address of the AdGuard Home web interface, then the user dumbmonit and its password.

Vendor documentation: https://github.com/AdguardTeam/AdGuardHome/wiki/Configuration#password-reset

AdGuard Home has no read-only account and no screen to manage users: every user listed in AdGuardHome.yaml can change every setting. Give DumbMonit a user of its own, so it can be removed without touching yours. AdGuardHome.yaml sits next to the AdGuardHome binary, or in the conf folder of the Docker volume. Add the line under users:, at the same indentation as the - name: line already there, and replace HASH with what htpasswd printed after dumbmonit:. The section then reads:

users:
- { name: dumbmonit, password: "$2y$10$…" }
- name: yourname
password: $2a$10$…

To check from the DumbMonit host that the user is accepted:

curl -u dumbmonit http://adguard.lan/control/status

DumbMonit only reads the status, the statistics, the filter lists and the last version check. It never reads the query log. At every check it asks AdGuard Home to test each upstream DNS server, as the Test upstreams button does; untick Test upstream servers in the options to stop that. After five wrong passwords, AdGuard Home refuses the address for 15 minutes.

AdGuard Home must be stopped while you edit the file: it rewrites AdGuardHome.yaml whenever a setting changes, and would drop a line added while it runs.

CredentialFields
User name / passwordThe dedicated user added to AdGuardHome.yaml, sent as HTTP basic authentication.
No authenticationOnly for an AdGuard Home with no user at all in AdGuardHome.yaml.

Address: a host name or IP (adguard.lan), host:port, or a full URL with a path prefix behind a reverse proxy (https://dns.lan/adguard); a trailing /control is ignored. Options: protocol (HTTP by default), port (80), certificate check, request timeout (5 s) and the upstream test (on).

CallWhy
GET /control/statusrunning, protection, version: the only call whose failure fails the check
GET /control/stats, GET /control/stats/configqueries, blocks, upstream answers, statistics window
GET /control/filtering/statusfilter lists
POST /control/version.json with {"recheck_now": false}the result of the last version check, as the web interface reads it on every page load; it never forces a new check
GET /control/dns_info, then POST /control/test_upstream_dns once per upstreamthe configured upstreams and bootstrap servers, then the upstream test; changes no setting