Blacklist and Whitelist API
Base URLs:
- Through the
webreverse proxy (recommended):https://localhost:8443/api - Directly to the backend (localhost only):
http://127.0.0.1:5001/api
All endpoints require authentication (Basic or JWT). All response bodies follow the envelope {"status": "success" | "error", "data": ..., "detail": ...}.
IP blacklist
List entries
GET /api/ip-blacklist{
"status": "success",
"data": [
{
"id": 1,
"ip": "203.0.113.5",
"description": "known malicious",
"added_date": "2026-03-01T12:00:00"
}
]
}Add entry
POST /api/ip-blacklist{
"ip": "203.0.113.0/24",
"description": "optional description"
}ip accepts a single address or a CIDR range. Wildcards are not supported for IPs.
Delete entry
DELETE /api/ip-blacklist/{id}Bulk delete
POST /api/ip-blacklist/bulk-delete{ "ids": [1, 2, 3] }Clear all
DELETE /api/ip-blacklist/clear-allImport (per-type)
POST /api/ip-blacklist/importSame body as the unified /api/blacklists/import endpoint, with type defaulted to "ip".
Domain blacklist
List entries
GET /api/domain-blacklist{
"status": "success",
"data": [
{
"id": 1,
"domain": "malicious.example",
"description": "",
"added_date": "2026-03-01T12:00:00"
}
]
}Add entry
POST /api/domain-blacklist{
"domain": "*.ads.example.com",
"description": "optional description"
}domain accepts an exact FQDN or a wildcard subdomain pattern (*.example.com). A URL is reduced to its hostname (a port is dropped). Anything else is refused with 400: only letters, digits, hyphens, underscores and dots are allowed, with labels of 1-63 characters and no more than 253 in all. In particular, whitespace, tabs, newlines and colons are refused, because entries are written one per line into the proxy and DNS files.
Delete entry
DELETE /api/domain-blacklist/{id}Bulk delete
POST /api/domain-blacklist/bulk-delete{ "ids": [1, 2, 3] }Clear all
DELETE /api/domain-blacklist/clear-allImport (per-type)
POST /api/domain-blacklist/importSame body as the unified /api/blacklists/import endpoint, with type defaulted to "domain".
Unified import
Import multiple entries from a URL or inline content.
POST /api/blacklists/importFrom URL:
{
"type": "domain",
"url": "https://example.com/domains.txt"
}Inline content:
{
"type": "ip",
"content": "192.0.2.1\n198.51.100.0/24\n203.0.113.5"
}type must be "domain" or "ip".
Response:
{
"status": "success",
"data": {
"added": 150,
"skipped": 3,
"errors": ["Invalid format: not-an-ip"]
}
}Supported file formats:
- Plain text, one entry per line.
- JSON array —
["entry1", "entry2"]. - JSON objects —
[{"domain": "example.com"}]. - Lines beginning with
#are ignored.
SSRF protection
Import URLs are validated. Hosts that resolve to loopback, private, link-local, multicast, or other special-purpose ranges are rejected, and the resolved IP is pinned to prevent DNS rebinding mid-download. The download is capped at 200 MB.
Geo import
POST /api/blacklists/import-geo{ "countries": ["RU", "CN", "KP"] }Country IP ranges are fetched from herrbischoff/country-ip-blocks (IPv4) and added to the IP blacklist.
IP whitelist
Whitelisted destination IPs bypass the direct-IP block rule in Squid.
List entries
GET /api/ip-whitelist{
"status": "success",
"data": [
{
"id": 1,
"ip": "192.168.1.50",
"description": "Home NAS",
"added_date": "2026-03-01T12:00:00"
}
]
}Add entry
POST /api/ip-whitelist{
"ip": "192.168.1.0/24",
"description": "LAN subnet"
}Delete entry
DELETE /api/ip-whitelist/{id}Domain whitelist
Whitelisted domains are excluded from the dnsmasq sinkhole, so they resolve normally even when present in the domain blacklist.
List entries
GET /api/domain-whitelist{
"status": "success",
"data": [
{
"id": 1,
"domain": "github.com",
"type": "fqdn",
"description": "Essential — code hosting",
"added_date": "2026-03-01T12:00:00"
}
]
}Add entry
POST /api/domain-whitelist{
"domain": "github.com",
"description": "Essential — code hosting"
}Delete entry
DELETE /api/domain-whitelist/{id}Egress allowlist
The egress allowlist is the deny-by-default complement to the blacklists. It is consulted only when default-deny egress is enabled (the egress_default_deny setting, default false). While that setting is off — the default — behaviour is unchanged: clients may reach any destination not on a blacklist, and this allowlist has no effect. When it is on, the proxy denies all outbound egress from local clients except destinations on this allowlist; everything else is refused with a Squid 403.
The egress_default_deny toggle is set via the bulk settings endpoint (POST /api/settings, flat {name: value} body), not through this group.
Each entry is either an IP/CIDR (matched by Squid dst) or a domain (matched by Squid dstdomain). The type is auto-classified on add: a value parseable as an IP or CIDR is stored as type cidr, otherwise it is treated as a domain.
List entries
GET /api/egress-allowlist{
"status": "success",
"data": [
{
"id": 1,
"entry": "acme-v02.api.example",
"type": "domain",
"description": "ACME server",
"added_date": "2026-03-01T12:00:00"
}
]
}Add entry
POST /api/egress-allowlist{
"entry": "203.0.113.0/24",
"description": "optional description"
}entry accepts an IP, a CIDR range, or a domain; the type is auto-classified to cidr or domain.
Success:
{
"status": "success",
"message": "Entry added to egress allowlist"
}A 400 is returned with "entry must be an IP, CIDR, or domain" when entry is empty, whitespace, or otherwise invalid, and with "entry already in allowlist" on a duplicate.
Delete entry
DELETE /api/egress-allowlist/{id}Bulk delete
POST /api/egress-allowlist/bulk-delete{ "ids": [1, 2, 3] }Clear all
DELETE /api/egress-allowlist/clear-all