Setup guide
AdGuard Home blocklist of malicious domains, as an authenticated DNS blocklist
No credit card required · Free API key
On this page08
What you get
AdGuard Home filters names, so only the domain lists apply. The adblock form, ||domain^, blocks each domain and its subdomains; load one form per tier.
| List | Entries | Rebuilt | Plans |
|---|---|---|---|
| blocklist-domains-critical-adguard.txtDefault. Domains listed by 6 or more threat sources, or 3 or more with a critical category, with their subdomains. | about 2 million | every 12 h | Basic, Pro, and Enterprise |
| blocklist-domains-c2-adguard.txtCommand-and-control domains reported by C2 trackers, whatever their level. | about 22,000 | every 12 h | Basic, Pro, and Enterprise |
| blocklist-domains-ransomware-adguard.txtDomains in the ransomware category, whatever their level. | about 3,600 | every 12 h | Basic, Pro, and Enterprise |
| blocklist-domains-critical.txtThe critical tier in domains-only syntax: exact names, no subdomains. Load it instead of the adblock form, not with it. | about 2 million | every 12 h | Basic, Pro, and Enterprise |
Entries rounded from the build of ; each list is rebuilt every 12 hours. Today’s counts are public and need no key.
What each plan receives
- FreeFree account, or no key: the first 10% of each list, marked
X-Blocklist-Version: lite. - Basic, Pro, and EnterpriseBasic, Pro, and Enterprise: every list in full.
- Pro and EnterpriseTAXII 2.1 collections, for platforms that read STIX indicators: Pro and Enterprise.
GET https:/
Full list or 10% sample
| Field | Basic, Pro, and Enterprise | Free |
|---|---|---|
X-Blocklist-Version: | full | lite |
X-Blocklist-Percentage: | 100 | 10 |
Total entries: | <COUNT> | <COUNT> |
First lines of the file
! IsMalicious.com Blocklist - Domains (Critical)
! Format: AdGuard
! Generated: <BUILD_TIME>
! Total entries: <COUNT>
! Update frequency: every 12 hours
! Category: All
! Threat level: Critical
! Website: https://ismalicious.com
! © <YEAR> IsMalicious (compilation). Licensed to the downloading account under https://ismalicious.com/terms; redistribution of the compilation prohibited. Third-party entries remain under their providers' licences — see https://ismalicious.com/sources.
!Values in angle brackets are set by each build.
Prerequisites
- AdGuard Home v0.107.0 or later.
- The AdGuard Home admin login, for the API or the configuration file.
- An isMalicious API key and secret, from Account › API access.
- Outbound HTTPS (TCP 443) over IPv4 from AdGuard Home to
api.ismalicious.com, which has no IPv6 address.
Set it up
Copy your API key and secret
Open Account › API access and copy the API Key and the API Secret. The full list needs a Basic, Pro, or Enterprise plan; a Free key loads the 10% sample.Build the list URL
Put the key, a colon and the secret before the host, followed by@. Keys and secrets are UUIDs, so they need no encoding. Useapi.ismalicious.com: the ismalicious.com edge refuses some sources with a 403.List URLURL https://<API_KEY>:<API_SECRET>@api.ismalicious.com/blocklist/download/blocklist-domains-critical-adguard.txtAdd it as a custom blocklist
Filters › DNS blocklists › Add blocklist › Add a custom list. Enter the nameisMalicious critical, paste the URL in Enter a URL or an absolute path of the list, then Save. AdGuard Home downloads the list at once and reports its rule count.Set the update interval to 12 hours
Settings › General settings › Filter update interval: 12 hours. The options are Disabled, 1 hour, 12 hours, 1 day, 3 days and 7 days; the setting saves on change. The default is 1 day, and the interval applies to every list you load.Or script it (optional)
The/controlAPI takes the same list and interval with the admin login; run it on the AdGuard Home host, where the interface answers over plain HTTP unless encryption is configured. InAdGuardHome.yaml, merge the excerpt into the existingfiltersandfilteringkeys with AdGuard Home stopped: a secondfiltersorfilteringkey stops AdGuard Home from starting, and it overwrites changes made while it runs.AdGuard Home APIsh # On the AdGuard Home host: the interface is plain HTTP unless encryption is # configured. curl asks for the admin password, so it stays out of ps. AGH=http://127.0.0.1:<ADMIN_PORT> # body.json (mode 600), written with an editor, holds the list with the key: # {"name":"isMalicious critical","url":"https://<API_KEY>:<API_SECRET>@api.ismalicious.com/blocklist/download/blocklist-domains-critical-adguard.txt","whitelist":false} curl -fsS -u '<AGH_USER>' -H 'Content-Type: application/json' \ -X POST "$AGH/control/filtering/add_url" --data @body.json curl -fsS -u '<AGH_USER>' -H 'Content-Type: application/json' \ -X POST "$AGH/control/filtering/config" --data '{"enabled":true,"interval":12}'AdGuardHome. yaml (excerpt to merge)yaml # Excerpt to MERGE into the existing keys, with AdGuard Home stopped: # never add a second filters: or filtering: key; keep filter ids unique. # v0.107.36 and older: filters_update_interval sits under dns:. filters: # ...your existing entries... - enabled: true url: https://<API_KEY>:<API_SECRET>@api.ismalicious.com/blocklist/download/blocklist-domains-critical-adguard.txt name: isMalicious critical id: 1700000001 filtering: # ...existing keys stay; change only: filters_update_interval: 12Keep the key out of AdGuard Home (optional)
- AdGuard Home stores the URL in clear in
AdGuardHome.yaml, shows it in the DNS blocklists table and prints it when a refresh fails. - To avoid that, fetch the list with the root-only script below, which refuses an error, a body that is not a list, the 10% sample and a file whose entry count differs from its header, and add the file’s absolute path instead of the URL.
- AdGuard Home reads the file again when the list is next due, or on Check for updates.
- Since v0.107.53 the file must sit in a directory that
filtering.safe_fs_patternsmatches:userfilters/in the work directory for a configuration made by the install wizard,data/userfilters/for one migrated from an older release.
Create the file, root-onlysh install -d -m 700 /etc/ismalicious [ -e /etc/ismalicious/netrc ] || install -m 600 /dev/null /etc/ismalicious/netrc chmod 600 /etc/ismalicious/netrc # Then write the three lines below into it with an editor, unless it holds them already./ etc/ ismalicious/ netrcnetrc machine api.ismalicious.com login <API_KEY> password <API_SECRET>/ usr/ local/ sbin/ ismalicious-fetch. shsh #!/bin/sh # Runs as root every 12 hours. /etc/ismalicious/netrc (mode 600) holds the key. # DIR must match filtering.safe_fs_patterns; on Docker, use the host directory # mounted on /opt/adguardhome/work, plus /userfilters. set -eu NETRC=/etc/ismalicious/netrc DIR=/opt/AdGuardHome/userfilters FILE=blocklist-domains-critical-adguard.txt # fetch_list LIST OUT: download one list to OUT and check it. # On any failure OUT is removed and the function returns 1. fetch_list() { if ! code=$(curl --silent --show-error --fail --netrc-file "$NETRC" \ --proto '=https' --max-time 300 --retry 2 \ --output "$2" --write-out '%{http_code}' "https://api.ismalicious.com/blocklist/download/$1"); then rm -f "$2"; echo "$1: download failed" >&2; return 1 fi if [ "$code" != 200 ]; then rm -f "$2"; echo "$1: HTTP $code" >&2; return 1 fi if ! head -n 1 "$2" | grep -q '^[#!] IsMalicious.com Blocklist'; then rm -f "$2"; echo "$1: not an isMalicious list" >&2; return 1 fi if grep -q 'Lite Version' "$2"; then rm -f "$2"; echo "$1: lite list received, check the API key and the plan" >&2 return 1 fi # Every entry ends with a newline, and one header counts them: refuse a # cut, doubled or empty file. if [ -n "$(tail -c 1 "$2")" ]; then rm -f "$2"; echo "$1: cut short, no final newline" >&2; return 1 fi if [ "$(grep -c '^[#!] Total entries:' "$2")" != 1 ]; then rm -f "$2"; echo "$1: not one Total entries line" >&2; return 1 fi total=$(sed -n 's/^[#!] Total entries: \([0-9,]*\)$/\1/p' "$2" | tr -d ,) got=$(grep -c '^[^#!]' "$2" || true) if [ -z "$total" ] || [ "$total" = 0 ] || [ "$got" != "$total" ]; then rm -f "$2"; echo "$1: $got entries, the header says ${total:-none}" >&2 return 1 fi } mkdir -p "$DIR" tmp=$(mktemp "$DIR/.$FILE.XXXXXX") trap 'rm -f "$tmp"' EXIT fetch_list "$FILE" "$tmp" chmod 644 "$tmp" mv -f "$tmp" "$DIR/$FILE" # Schedule it in /etc/cron.d/ismalicious-adguard: # 7 5,17 * * * root /usr/local/sbin/ismalicious-fetch.sh # List path in AdGuard Home: /opt/AdGuardHome/userfilters/blocklist-domains-critical-adguard.txt- AdGuard Home stores the URL in clear in
Verify it works
- Filters › DNS blocklists shows the list’s Rules count and Last time updated.
- Rules count matches the
countof the plain file of the same tier in /blocklist/stats, give or take one rebuild; the stats list plain files only. About a tenth of it is the 10% sample. - Last time updated is not proof of success: it moves on a failure too when another list updated in the same pass. Look for
updating filtererrors in the log rather than trusting the date. - Filters › Custom filtering rules › Check the filtering with a domain from the list names the list and the rule that matched.
- In the Query log, blocked queries show the list name.
# Rules count and last update of every list (curl asks for the password):
curl -fsS -u '<AGH_USER>' "http://127.0.0.1:<ADMIN_PORT>/control/filtering/status"
# The list itself, as root with the netrc file: no "Lite Version" in its header.
sudo curl -sS --netrc-file /etc/ismalicious/netrc "https://api.ismalicious.com/blocklist/download/blocklist-domains-critical-adguard.txt" | head -12Troubleshooting
“got status code 401, want 200”
The key or the secret is wrong or incomplete. The message appears when you add the list, and as an updating filter log line on a scheduled refresh; both print the URL, credentials included, so clear them from logs you share. The previous copy stays active. The response body reads “Blocklist not found or empty”; trust the status code. Copy both values again from Account › API access.
Only about 10% of the rules load
The URL carries no credentials, or the plan is Free or lapsed: past due, unpaid, canceled, incomplete or paused counts as Free. Compare the rules count with /blocklist/stats.
The local copy script prints “entries, the header says”, “cut short, no final newline” or “not one Total entries line”
The file was empty, cut short or not one of the lists, as a proxy or captive portal answers. The script keeps the previous copy and exits 1; the next run tries again.
A timeout or a 502
A download that takes longer than 30 seconds on our side ends in a timeout or a 502: use a tier or category list from the table.
“cannot read more than 268435456 bytes”
AdGuard Home v0.107.78 and later refuse a list larger than filtering.max_http_size, 256 MB by default: adding it fails, or a refresh fails and the previous copy stays. Use a smaller tier rather than raising the limit. Older releases have no cap.
503 Service Unavailable
The list is being built for the first time, and the response carries Retry-After: 600. AdGuard Home ignores it and keeps the previous copy.
The list does not reload after you fix the cause
When other lists refreshed at the same check, AdGuard Home marks ours as attempted and waits a full interval. When every due list fails, it doubles its check interval from 1 hour, with no ceiling: 2 hours, 4, 8… Click Check for updates once the cause is fixed.
“data is HTML, not plain text”
A page answered with a 200 instead of the list: a captive portal, a proxy or a TLS inspection page. An edge refusal from an ismalicious.com mirror is a 403 instead (“got status code 403, want 200”). Use api.ismalicious.com, and exempt it from TLS inspection.
“likely binary character”
The header lines are not the cause: AdGuard Home skips # and ! lines. A control character means a corrupted download: run Check for updates again.
x509: certificate signed by unknown authority
AdGuard Home always verifies the certificate. Update the system CA bundle (on Entware routers, /opt/etc/ssl/certs), check the clock, and exempt api.ismalicious.com from TLS inspection.
“net/url: invalid userinfo” or “bad http(s) url”
Leftover brackets of the placeholders give “net/url: invalid userinfo”: remove them, and any space. “bad http(s) url” is a scheme error, or a file:// address: a local list takes a plain absolute path.
Limits
- AdGuard Home keeps the URL, credentials included, in
AdGuardHome.yaml, in the DNS blocklists table and in its filter status. It prints it in the log when a refresh fails and in the error when adding the list fails. The local-file variant of the last step avoids that. - One update interval covers every list: 12 hours also applies to the other lists you load.
- Only the adblock form blocks subdomains; the plain and hosts forms block exact names. No wildcard entries are served, and AdGuard Home needs none:
||domain^covers the subdomains. - AdGuard Home v0.107.78 and later refuse a list past 256 MB (
filtering.max_http_size).blocklist-domains-all.txtis about 386 MB in plain form, so do not load it. - AdGuard Home is not a firewall: it can block a DNS answer by its address, but a bare IP line in a list is a pattern, not an address to block. Do not load
blocklist-ips-*lists; use a firewall for those. - The 10% sample is the first tenth of an unsorted file, not the riskiest tenth.
- No RPZ and no CIDR are served; AdGuard Home needs neither for domain lists.
Questions
Can AdGuard Home send an API key for a blocklist?
Yes. Put the key and the secret before the host in the list URL, separated by a colon and followed by @. AdGuard Home fetches the list with Go’s HTTP client, which sends them as HTTP Basic. The URL is stored in clear in AdGuardHome.yaml; a local file fetched by a script keeps the key out.
Which file blocks subdomains?
The -adguard.txt form. AdGuard Home reads its ||domain^ rules as the domain and all its subdomains. The plain and hosts forms block the exact names only.
How often does AdGuard Home refresh the list?
At its filter update interval, 1 day by default, which applies to every list. Set it to 12 hours: the lists are rebuilt every 12 hours, so refreshing more often downloads the same file again.
Can AdGuard Home use the IP lists?
Load only the domain lists. AdGuard Home is not a firewall: a bare IP line in a list is a pattern, not an address to block. Block IP addresses on a firewall.
What does a free account load into AdGuard Home?
The first 10% of each list. AdGuard Home loads it without an error, so compare the rules count with the published count. The full list needs a Basic, Pro, or Enterprise plan.
Related
Threat domains as an authenticated adlist
Every list, level and category
TAXII 2.1 collections for SIEMs and TIPs
Authentication, endpoints and limits
Check one domain before you block it
Get Started
Ready to get started?
No credit card required · Free API key