Quick start
From zero to a network that blocks ads and trackers on every device.
curl -fsSL https://get.purge.cc | sudo sh
On Debian, a standard install has no curl: run sudo apt-get install curl first, or use wget -qO- https://get.purge.cc | sudo sh. See Debian / Ubuntu.
You need one always-on Linux machine with systemd, such as a spare PC or a home server. The command installs Warden, starts it, and waits until it blocks a test domain. Nothing on the network changes until you point your router or a device at this machine.
This is an install for a host without Warden. If Warden 0.41.x or newer already runs here, use the upgrade instead. Without --upgrade, the installer refuses a host that already has Warden and says what to run instead. A configuration kept by the uninstaller is the exception: the installer adopts it. See Reinstall over a kept configuration.
What the installer does
It downloads a checked bundle, then runs the installer inside it.
curl … | sudo sh runs a small script that downloads the bundle of the current release for x86_64, checks it against the SHA-256 sum published next to it, unpacks it to /usr/local/lib/purge-warden, and hands over to scripts/install.sh in the bundle. No package is installed for Warden itself.
The installer then:
| # | Step |
|---|---|
| 1 | Checks the host: systemd, a supported distribution, DNS and network reachability, free disk space |
| 2 | Shows what it will do and asks you to confirm. Add --yes to skip the prompt. Without a terminal it goes on without asking, except at port 53 |
| 3 | Installs ca-certificates and dig (dnsutils on Debian and Ubuntu, bind-utils on Fedora) |
| 4 | Installs the daemon to /usr/local/libexec/purge-warden/warden and a warden command to /usr/local/bin/warden |
| 5 | Runs warden init: creates the purge-warden user, the directories, and /etc/purge-warden/config.toml with the default lists. A configuration kept by the uninstaller is checked and kept instead: see Reinstall over a kept configuration |
| 6 | Creates the admin token, saved to /var/lib/purge-warden/token |
| 7 | Installs the systemd unit, enables it and starts it. It also starts the hourly backup timer, which writes no backup until you set [backup] auto_interval: see Automatic backups |
| 8 | Waits for the daemon to answer, then checks that google.com resolves and doubleclick.net is blocked |
Supported distributions: Debian 12 or newer, Ubuntu 22.04 or newer, Fedora 40 or newer, and RHEL 9 and rebuilds such as Rocky and Alma. The bundle is for x86_64 only. An aarch64 machine, such as a Raspberry Pi with a 64-bit system, has no bundle: build from source instead.
The default lists need about 700 MB of RAM, and about 1.4 GB for a few seconds when a list update rebuilds them. A small machine, such as a Raspberry Pi, can run Warden only with a small set of lists: see Memory and list size.
Two things the installer decides for you, and how to change them:
- Who may query the resolver. It allows the LAN it finds on your default route, plus loopback. If it cannot find a LAN, it stops with an error. Run it again with
--lan-cidr 192.168.1.0/24. For two networks, separate them with commas. - Which upstream resolver Warden forwards to. Warden never picks a provider for you. The installer reads the resolver this machine already uses. If it finds none,
warden initrefuses withno upstream resolver configured. Pass one yourself, as plain DNS:--upstream 192.0.2.53:53.
Options go after --:
curl -fsSL https://get.purge.cc | sudo sh -s -- --lan-cidr 192.168.1.0/24 --upstream 192.0.2.53:53The other options are --listen <addr:port>, --lists <csv> and --dry-run, which shows every action and changes nothing.
--lan-cidr, --upstream, --listen and --lists only shape a new configuration. The installer does not look for a LAN when it adopts a kept configuration, and these options do not change that configuration.
Port 53
If systemd-resolved holds port 53 (common on Ubuntu and Fedora Workstation), the installer asks whether to disable only the stub listener. It asks during the host check, before it shows the plan. With --yes it does so without asking. Without a terminal and without --yes, it stops there with status 1 and changes nothing; run it again with --yes. The change itself comes later, after the terms and the configuration check, so an install that stops before then leaves systemd-resolved as it was. It writes /etc/systemd/resolved.conf.d/purge-warden-no-stub.conf, restarts systemd-resolved, and, if /etc/resolv.conf pointed at the stub, points it at the real upstream servers instead.
If another service holds port 53, such as dnsmasq, bind9 or Pi-hole, the installer stops and tells you to stop that service first. On Fedora and RHEL with firewalld running, it opens DNS (53/tcp and 53/udp) in the default zone.
Check the status
These commands run on the Warden machine itself.
The installer ends with a summary and its own checks. To look again later:
warden status confirms the daemon is up. warden query names the list that caught a domain. For a live view, run warden dashboard. Ads, trackers, and malware are already subscribed. More lists: Import lists.
On the first run the daemon downloads its lists before it answers. The installer waits up to 600 seconds for the listener, then up to 600 seconds for the first block. On a slow link, raise the first wait with PURGE_LISTENER_TIMEOUT and the second with BLOCK_VERIFY_TIMEOUT_SECS. See Environment variables.
If the daemon is still loading its lists when the first wait ends, the installer stops with status 3. Nothing failed: Warden is installed and keeps loading. The installer skips its DNS checks and prints the commands to follow the start:
If the installer exits with status 5, the daemon stopped while it was starting, google.com did not resolve, or doubleclick.net was not blocked. See Troubleshooting.
Installer exit statuses
| Status | Meaning |
|---|---|
0 | Installed, and both DNS checks passed. A --dry-run that finds nothing to refuse, --help, and an answer that does not start with y at the terms prompt also exit with 0 and do not install Warden. With --help or a declined prompt, the bundle is already unpacked in /usr/local/lib/purge-warden; a --dry-run leaves it untouched. |
2 | An option is unknown or has no value. The message says which. |
3 | Installed, but the daemon was still loading its lists when the wait ended, so the DNS checks were skipped. Nothing failed. |
5 | Installed, but a DNS check failed, or the daemon stopped while it was starting. |
6 | A kept configuration does not load with the new version. The daemon was not installed: see Reinstall over a kept configuration. |
| any other non-zero | Refused or failed. The message says which. |
The status is that of sudo sh. If curl or wget fails before the script starts, for example because it is not installed or cannot reach get.purge.cc, sh reads an empty script and the command exits with 0. Nothing is installed: read the lines above the status.
With --upgrade, statuses 2 and 3 mean that the upgrade refused before it changed anything. The upgrade has statuses of its own: see Upgrade.
Point your network at it
A device is protected the moment its DNS goes to this machine.
| Scope | What you change | When |
|---|---|---|
| Whole network (recommended) | Router LAN / DHCP DNS → the Warden machine’s IP | Every device that gets settings from the router |
| One device | That device’s DNS → the same IP | To try it first |
On the router: admin page (often http://192.168.1.1) → LAN / DHCP DNS → the Warden machine’s IP. Save, reconnect a client. The field you want is the DNS handed out to clients, not WAN.
Give the machine a static IP, or reserve it in DHCP. If the address later moves, the whole network loses DNS.
On a single device: network settings → DNS servers (phones: Wi-Fi → configure DNS → manual). Revert the same way; nothing else is affected.
The installer sets server.allow_from to your LAN plus loopback. To add or change networks later, see Basic configuration.
1.1.1.1, 9.9.9.9) keeps the internet up, but those lookups skip Warden. Leave the secondary blank if you want no leak.Confirm it’s working
From a device you just pointed — not the Warden machine.
Ad-heavy pages should come back with blank banners. Or query through the Warden machine:
If you still get a real address, that device is not using Warden yet — recheck its DNS and reconnect.
Running warden as yourself
The daemon owns its configuration and control socket, so warden must run as the purge-warden user. The installed /usr/local/bin/warden does that for you, so warden status works from your own shell, over ssh, from cron and from scripts. sudo -u purge-warden warden status always works too.
The real daemon binary is /usr/local/libexec/purge-warden/warden. It is deliberately not on PATH. A few commands, such as warden config relocate, need it directly and must run as root.
Remove Warden
The bundle ships its own uninstaller.
sudo /usr/local/lib/purge-warden/scripts/uninstall.shBy default it keeps /etc/purge-warden, /var/lib/purge-warden (your configuration, admin token, list cache and statistics) and the purge-warden user. The next install adopts that configuration: see Reinstall over a kept configuration.
- Add
--purgeto delete both directories, thepurge-wardenuser, and the user’s home directory if the installer created it. - Add
--restore-resolvedto put back thesystemd-resolvedstub listener. If the installer had pointed/etc/resolv.confaway from the stub, the uninstaller points it back, but only if the stub listens again right after the uninstaller restartssystemd-resolved. Otherwise it warns and leaves the file as it is. A regular file, or a relative link as your distribution writes it, is left alone. A link you wrote yourself to the absolute path/run/systemd/resolve/resolv.conflooks like the installer’s, so the uninstaller points it at the stub as well. - Add
--dry-runto preview.
The uninstaller never deletes the bundle in /usr/local/lib/purge-warden, because it runs from there. After --purge it prints the command that removes it.
On Fedora and RHEL with firewalld running, the installer opened DNS, and the uninstaller leaves the firewall as it is. If firewalld still allows DNS, the uninstaller says so and prints the command that closes it. Run it only if nothing else on this host serves DNS:
sudo firewall-cmd --permanent --remove-service=dns && sudo firewall-cmd --reloadWithout --purge, the uninstaller refuses and removes nothing while a configuration change is unfinished: a migration, a policy write, or a warden config relocate run. The next install could not adopt that configuration. The message names a command that shows how to finish the change or roll it back. With --purge it goes ahead and deletes the configuration too.
It also removes the .s6-old files that a killed upgrade leaves next to the binary and the service unit. After that, the killed upgrade can no longer be recovered: see A killed or crashed upgrade.
The uninstaller asks Proceed with uninstall? [y/N] on your terminal. Without a terminal (for example ssh host sudo ... with no tty, or a script), it stops with exit code 1 and removes nothing. Add --yes (or -y) to skip the question.
Reinstall over a kept configuration
Run the install command again. When the installer finds a configuration and the purge-warden user, but no Warden binary and no service unit, it treats the configuration as one the uninstaller kept. It says so, then keeps the configuration, the admin token and the list cache. Before it installs the daemon, it checks the configuration with the new version.
If the check fails, the installer stops with status 6, before it installs the daemon or changes systemd-resolved. It prints the error and the schema version it found:
| Schema found | What to do |
|---|---|
| 5 | Fix what the error names, then run the install again. |
| 4 (kept from Warden 0.41.x) | Migrate it to schema 5 with the binary of the new release, then run the install again. Follow “Schema-4 config kept by uninstall.sh” in /usr/local/lib/purge-warden/docs/UPGRADE_RECOVERY.md. |
| 3 | No route keeps it. Start from scratch. |
| unknown | If the error names something to fix, fix it and run the install again. Otherwise start from scratch. |
install.sh --upgrade cannot help here: nothing else of Warden is installed. A host that still runs 0.41.x should upgrade in place with --upgrade, not uninstall first.
To start from scratch, delete the kept configuration and install again:
sudo /usr/local/lib/purge-warden/scripts/uninstall.sh --purge--purge deletes /etc/purge-warden and /var/lib/purge-warden: the configuration with its device list, the admin token, the list cache, the statistics and any backups kept there. It also removes the purge-warden user and its home directory.
A --dry-run does not run this check. If the purge-warden user is gone but the configuration is still there, the installer cannot adopt it: it stops and prints the useradd command that recreates the user.
Next steps
Warden is filtering with sensible defaults. Tailor it from here.
- Profiles — different filtering for kids, guests, or work devices.
- Import lists — subscribe to more lists, or add your own.
- Devices — pin a specific device to a profile.
- Upgrade — move to a newer release.