EN
  • English
  • Deutsch
  • Polski
  • Italiano
  • Español

Import lists

Under review — wording may still change.

Subscribe to a feed of domains — from the purge.cc catalog or from any URL you trust — then let each profile decide what to do with it.

What this step does

A list is a feed of domains. It carries no allow/deny nature of its own beyond a default: base on its [[blocklists]] row, which is deny unless you say otherwise. What actually happens to a list’s domains is decided per profile — profiles.<id>.lists maps a list id to deny, allow or ignore, and that override wins. With no override, the profile inherits base. One function answers the question for a (profile, list) pair: src/config/schema/blocklist.rs → effective_direction().

So a list is not an “allowlist” or a “blocklist”. It is a list, and the profile decides its nature. This page subscribes you to one, then points a profile at it.

Add a list

Browse the catalog

bash
warden lists catalog
warden lists catalog --scope privacy

The four scopes are privacy, security, content and services. Rows already in your config are marked [active]:

text
purge.cc list catalog (5 lists, offline — using built-in data)

privacy (5 lists):
  privacy/ads             ads               [active]
  privacy/devices         devices
  privacy/general         general
  privacy/mobile          mobile
  privacy/tracking        tracking          [active]

usage: warden lists add <list-id>

With network access the catalog is fetched live and each row carries a domain count. Because warden lists add resolves slugs offline, a list newer than your binary is marked [newer than this build] and printed with the URL to use instead.

Add one from the catalog

bash
warden lists add privacy/ads
text
added: privacy/ads (list "privacy-ads")
run `warden blocklist show privacy-ads` to check what it filters for

The id is the slug with its slash turned into a dash, so privacy/ads becomes privacy-ads — the same id warden init writes for the lists it subscribes you to, and the id you will type everywhere else.

Add any URL

bash
warden lists add https://lists.example.org/ads.txt

The id is derived from the host and the file name — https://lists.example.org/ads.txt becomes lists-example-org-ads. Both halves are kept because either alone collides too easily. Any port and userinfo are dropped, anything outside a-z0-9- collapses to a dash, and the result is capped at 64 characters.

Two things can come back instead of a new subscription:

The URL is already subscribed. Not an error — re-running an install script should be quiet:

text
already subscribed: https://lists.example.org/ads.txt (list "lists-example-org-ads")

The derived id is taken by a different list. Two URLs on one host can genuinely reduce to one id, so this is refused rather than silently reported as success:

text
"https://lists.example.org/trackers/list.txt" would be named "lists-example-org-list", which is already taken by a different list (https://lists.example.org/ads/list.txt). Add it with a name of your own:
  warden blocklist add <name> --url https://lists.example.org/trackers/list.txt

Do what it says: run warden blocklist add and choose the id yourself.

Which URLs are refused

warden lists add, warden blocklist add, warden blocklist set url and the TUI form refuse a source that is not safe to fetch: plain http://, a private or loopback address, or a URL with a user name or password in it. Use https:// with a public host. For a file on this machine, use warden blocklist import-local instead; the error message says so.

What is inside a list file

List entries are plain ASCII domains. For an internationalised name, a list entry must be in xn-- form, for example xn--mnchen-3ya.de for münchen.de. An entry written in Unicode is dropped. No [[blocklists]] list can use @@, wildcards, regex or $important, whether it comes from a URL or from import-local: those lines are skipped. Write them in a Custom List.

What happens next

The list starts filtering, and there is no second step. Nothing was written into any profile — warden lists add does not attach the list to your default profile or to any other. It filters because base on the new row defaults to deny, and a profile with no override for that list inherits base.

One older channel behaves differently. If a subscription is recorded in the [lists].sources array — the form this verb used to write — it downloads on schedule and filters nothing, because no profile can reach it. warden lists add says so when it finds one, and warden lists list flags them under inactive entries in [lists].sources. Convert one by removing it and adding it again:

bash
warden lists remove https://lists.example.org/ads.txt
warden lists add https://lists.example.org/ads.txt

Let the profile decide

Override base for one profile, ask what is in force, or drop the override again:

bash
warden profile list-policy show kids
warden profile list-policy set kids privacy-ads allow
warden profile list-policy clear kids privacy-ads

The same thing in the config file:

config.toml
toml
[profiles.kids]
lists = { privacy-ads = "allow" }

clear and set … ignore are not the same move:

You wantUseWhat it means later
This profile never uses this listset <profile> <list> ignoreA standing declaration. It survives a change to base.
This profile follows the list’s own defaultclear <profile> <list>The key is dropped. The pair follows base wherever it goes.

set and clear both go over the daemon socket, never by direct file edit, and the daemon re-validates the whole config before the write lands. So a typo is refused before anything reaches disk — and a two-list change with one bad id writes neither.

A profile naming a list id that no [[blocklists]] row declares is an error, not a warning. Over the socket it is refused before the write; in a hand-edited file it fails at load:

text
profile "kids" names blocklist "privacy-ad" in its list policy, but no [[blocklists]] entry with that id is configured. Run `warden blocklist list` to see what is.

profile "kids" sets lists.privacy-ad but no [[blocklists]] entry has id "privacy-ad"
  suggestion: add a [[blocklists]] entry with that id, or remove the entry from this profile's `lists`
An allow-direction list you did not author needs an explicit acknowledgement

Pointing a profile at a list with allow means that feed can unblock domains on your network. If the list is not trust = "local", Warden refuses the allow until you declare on the list that you accept that: accept_unsigned_allow = true on its [[blocklists]] row, or --accept-unsigned-allow on warden blocklist add, set-kind or set-trust. A profile override cannot declare it; the refusal suggests warden blocklist set-trust <list> remote-unsigned --accept-unsigned-allow. Whoever publishes that feed can add a domain to it tomorrow and it will be permitted here.

deny and ignore are not gated: both narrow what a profile permits, so there is nothing to declare.

Import a local file

For a list you wrote yourself, or one you downloaded and want to keep frozen:

bash
warden blocklist import-local ./office-deny.txt --id office-deny --kind deny
text
Imported '/etc/purge-warden/lists/office-deny.txt' as blocklist 'office-deny' (kind=deny, 412 entries).

The file is copied into the directory Warden manages for lists — lists/<id>.txt beside your config, so /etc/purge-warden/lists/office-deny.txt on a fresh install (/var/lib/purge-warden/lists/office-deny.txt on a host that still keeps its config there) — and registered with trust = "local". The format is detected from the content. --kind accepts deny, allow or ignore here. Because the result is local, an allow import needs no acknowledgement.

Editing the copy afterwards means editing the copy, not your original.

warden lists or warden blocklist?

Both families write the same object. warden lists add calls the same writer warden blocklist add does, so a list added either way is one [[blocklists]] row with the same validation and the same audit record.

warden lists …warden blocklist …
What it isThe subscription front doorDirect CRUD on [[blocklists]] rows
You name a list byCatalog slug or URLIts id
The id isDerived for youYours to choose
Also coversThe catalog, refresh, the download cacheset-kind, set-trust, import-local
Reachability probe on addSkipped, so a server that is down today does not block the subscriptionRuns, unless --skip-head-check

Note that the flag is spelled --kind while the field it writes is base. They are the same thing: the list’s own default direction.

Memory and list size

Warden holds every subscribed domain in memory. Memory grows with the number of unique domains, not with the number of lists: a domain on two lists counts once. warden status prints that number on its domains: line, and warden lists catalog shows each list’s count when it can fetch the catalog.

Measured on Warden 0.44.5 on 2026-10-24, on an x86_64 VM with 2 vCPU and 2.7 GB of RAM running Ubuntu 26.04:

List setDomainsSteadyPeak at a rebuild
The default set: security/malicious, privacy/ads, privacy/tracking15.3 millionabout 700 MBabout 1.4 GB
privacy/ads alone7.1 millionabout 330 MBabout 700 MB
  • Steady is the daemon’s resident memory once the lists are loaded: about 25 MB plus 45 MB per million domains. The first start and a restart stay close to it.
  • Peak at a rebuild is a little over twice the steady figure, for a few seconds. A rebuild runs when a refresh finds a changed list, and at a reload that changes the list set or how any profile uses a list. A refresh that finds no change does not rebuild. Right after a rebuild, memory can sit about 20% above the steady figure.

Size the host for the peak, plus what the system and other services use. A host with less memory can install Warden and run for days, then lose the daemon to the kernel’s out-of-memory killer at the first list update. To size another set, add up the catalog counts of its lists and apply the same rule. Lists overlap, so the sum is an upper bound. On a machine with 1 GB of RAM, such as a small Raspberry Pi, even privacy/ads alone leaves little room at a rebuild: choose smaller lists.

The figures depend on the build and the host, so treat them as a guide. To check your own host:

bash
warden status | grep domains:
grep -E 'VmRSS|VmHWM' /proc/$(systemctl show -p MainPID --value purge-warden)/status

VmRSS is the memory in use now. VmHWM is the highest value since the daemon started, so it shows the peak of the last rebuild.

CLI reference

VerbWhat it does
warden lists catalog [--scope <s>]Browse the purge.cc catalog, optionally one scope
warden lists add <slug|url>Subscribe. Derives the id, writes the [[blocklists]] row
warden lists listEvery configured source, plus any inactive legacy entry
warden lists refreshRe-download every list now, and rebuild the filter if a list changed
warden lists remove <slug|url|id>Unsubscribe, whichever channel the entry lives in. It does not reload: run sudo systemctl reload purge-warden. warden lists refresh keeps downloading the removed list
warden lists forget <slug|url>Drop the cached body and headers; config untouched
warden blocklist show <id>One list in full, including which profiles enforce it
warden blocklist add <id> --url <u>Register a subscription with an id and flags you choose
warden blocklist import-local <path> --id <id> --kind <deny|allow|ignore>Copy a local file in and register it as trust = "local"
warden blocklist set-kind <id> <deny|allow|ignore>Change the list’s base
warden profile list-policy set <profile> <list> <deny|allow|ignore>Override base for one profile
warden profile list-policy clear <profile> <list>Drop the override; follow base again
warden profile list-policy show <profile>What is in force for every list, and where it came from

In the TUI

Launch with warden dashboard, press 4 for the Filters section, then g i for the Lists leaf.

The leaf answers the same question warden blocklist show <id> does: for each list, the direction actually in force per profile, asked of effective_direction() rather than recomputed. If a list reaches nobody, both surfaces say so.

See also

  • Profiles — the canonical page for the entity that decides a list’s direction.
  • Create profiles — the next step: build the profiles whose policy you just set.
  • Custom rules — for domains you write yourself, with the full rule grammar, instead of subscribing to a feed.
  • Initialize — the three lists a fresh install already subscribes to.
  • Principles — why the whole list set lives in memory.
↑↓ to navigate · Enter to open · Esc to close See all results