Build from source
Compile Warden from source and install it on any Linux distribution.
Most people should install the package instead — it’s faster and upgrades cleanly. If your distribution has one, use the Debian / Ubuntu or Fedora guide. Build from source when there’s no package for your distribution (Arch, RHEL, openSUSE, …), when you want to turn on optional features, or when you need to target an older glibc than the prebuilt package supports.
Nothing here touches your network until the last step: you compile the binary, run warden init, drop in a hardened systemd unit, free up port 53, then start Warden and confirm it’s blocking.
Requirements
- A Linux distribution with
systemd - Architecture:
x86_64(aarch64 / ARM is cross-compile only — see the end) - Root /
sudo
Because you build on your own machine, the binary links whatever glibc that machine already has — so there’s no minimum-version hurdle the way there is with the prebuilt package. The build tools themselves are installed in the next step.
1. Install build tools
You need a C compiler, make, pkg-config, git, and a Rust toolchain (1.94 or newer). Warden’s TLS stack is pure Rust (rustls + ring) — there is no OpenSSL dependency to install.
# Fedora / RHEL
sudo dnf install gcc make pkg-config git
# Debian / Ubuntu
sudo apt install build-essential make pkg-config gitInstall Rust with rustup (the toolchain manager) if you don’t already have it:
curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh -s -- -y
source ~/.cargo/envYou’ll also want dig for the final check — it’s bind-utils on Fedora (usually pre-installed) and dnsutils on Debian / Ubuntu.
2. Get the source
git clone {{TODO: clone URL}}
cd wardenRun every command below from this directory — the build and install steps use paths relative to the repository root.
3. Build
cargo build --releaseThis produces the warden binary at target/release/warden — the daemon and the CLI in one executable.
Optional features are off by default. Turn one on at build time if you need it, for example cargo build --release --features dnssec (also doq and cluster).
4. Install
Install the binary and the systemd unit:
sudo install -m 0755 target/release/warden /usr/local/bin/warden
sudo install -m 0644 systemd/purge-warden.service /etc/systemd/system/
sudo systemctl daemon-reloadThat puts warden on PATH and installs the hardened unit (it runs as the unprivileged purge-warden user with CAP_NET_BIND_SERVICE so it can bind port 53 — no setcap step). It does not create a config. That is the next step.
init.Prefer a shortcut? sudo make install places the binary and the unit in one step. You still run warden init afterwards.
5. Initialize
warden init is required here. The package installer (get.purge.cc, .deb, .rpm) already created the purge-warden user, the state directories, and the first config.toml. Copying the binary does not. Skip this step and the daemon has nothing to load.
sudo warden init --yes--yes takes the defaults (three lists, private allow_from, profile default) and adopts this machine’s existing resolver as upstream if it can see one. Drop --yes to answer the prompts. If it refuses with no upstream resolver configured, pass --upstream:
sudo warden init --yes --upstream 192.0.2.53:53The prompts, what it writes, and the refusal messages: Initialize.
6. Free port 53 (if needed)
Check what holds port 53 first with sudo ss -ulpn 'sport = :53'. If nothing is listening there, skip this step. Otherwise, if this machine runs systemd-resolved on port 53 (common on desktop Linux), hand port 53 to Warden by disabling only the stub listener:
printf '[Resolve]\nDNSStubListener=no\n' | \
sudo tee /etc/systemd/resolved.conf.d/purge-warden-no-stub.conf
sudo systemctl restart systemd-resolved7. Enable + start
sudo systemctl enable --now purge-warden8. Verify
On first start Warden fetches its blocklists, so allow a few moments before doubleclick.net resolves to 0.0.0.0.
Point your router’s or devices’ DNS at this machine’s IP to protect the whole network.
Upgrading
Pull the latest source, rebuild, and replace the binary:
git pull
cargo build --release
sudo install -m 0755 target/release/warden /usr/local/bin/warden
sudo systemctl restart purge-wardenYour config in /var/lib/purge-warden/config.toml is preserved across upgrades. Do not re-run warden init. If a release ships a changed systemd unit, reinstall it as in step 4 and re-run sudo systemctl daemon-reload before restarting.
Removing
There’s no package manager to undo a source install, so remove the pieces by hand:
sudo systemctl disable --now purge-warden
sudo rm /usr/local/bin/warden /etc/systemd/system/purge-warden.service
sudo systemctl daemon-reloadThat stops and removes the program but leaves your config and data in /var/lib/purge-warden. For a clean slate, also delete that directory and the system user:
sudo rm -rf /var/lib/purge-warden
sudo userdel purge-wardenBuilding for ARM (aarch64)
ARM builds are cross-compiled and best-effort — not yet packaged or tested on real hardware. If you want to try, BUILDING.md in the repository documents the cross build --target aarch64-unknown-linux-musl route. Note that the shipped systemd unit’s syscall filter kills a static musl binary — it was rejected on x86_64 for exactly this reason — so an ARM build needs the unit’s hardening relaxed.
Older distributions (glibc < 2.39)
Building on the target machine sidesteps this entirely — cargo links whatever glibc is already installed, so a binary built on Ubuntu 22.04 runs on Ubuntu 22.04. The only hard floor is Rust 1.94, which rustup provides on any distro. You only need a build container or cargo-zigbuild tricks in BUILDING.md when cross-building on a newer host for an older target.