Skip to content

Files and paths

For an instance named after interface wg0:

Path Owner, mode What
/usr/local/bin/cerberd root 0755 the binary (daemon and CLI)
/etc/systemd/system/cerberd@.service root 0644 templated unit; cerberd@wg0 runs cerberd run wg0
/etc/sysusers.d/cerberd.conf root 0644 the cerberd system user
/etc/modules-load.d/cerberd.conf root 0644 loads wireguard at boot
/etc/cerberd/ root:cerberd 0750 configuration
/etc/cerberd/wg0.yaml root:cerberd 0640 instance config
/etc/cerberd/wg0.token root:cerberd 0640 TCP API bearer token (optional)
/etc/cerberd/routeros.pass root:cerberd 0640 RouterOS REST password
/var/lib/cerberd/ cerberd 0750 state (StateDirectory)
/var/lib/cerberd/wg0.db cerberd 0600 SQLite database: hub key, peers, keys, reservations, tags. Holds private keys
/run/cerberd/ cerberd 0750 runtime (RuntimeDirectory)
/run/cerberd/wg0.sock cerberd 0660 API socket for the CLI

Logs go to the journal: journalctl -u cerberd@wg0.

Each hub interface is its own instance with its own files: cerberd@wg1 ↔ /etc/cerberd/wg1.yaml ↔ /var/lib/cerberd/wg1.db ↔ /run/cerberd/wg1.sock. Pick one in the CLI with -i wg1.

cerberd@.service runs as cerberd:cerberd with only CAP_NET_ADMIN and a strict sandbox (ProtectSystem=strict, PrivateDevices, a @system-service syscall filter). Restart=on-failure, except exit code 78 (setup error). Stopping the unit leaves the interface up.

Don’t run wg-quick@wg0 next to cerberd@wg0: one writer per interface. The unit has no Conflicts= on purpose, since that would run wg-quick down and delete the interface cerberd adopts.