# Quadlet unit: Anubis bot-challenge proxy (rootless, boot-persistent). # # Install path on dankclaw: ~/.config/containers/systemd/anubis.container # Unit name: anubis.service (container name: anubis) # # Two-tier chain: the public Caddy listeners for the guarded vhosts proxy # everything to this container (port 8923, internal only — no published port, # so metrics on :9090 stay reachable only inside dankclaw_default); Anubis # verifies the client (challenge/DENY per policy) and forwards accepted # traffic back to Caddy's internal listener (TARGET below), where the normal # per-vhost routing — including Authentik forward_auth — resumes. Host headers # survive both hops, so vhost matching on the internal listener still works. # # Version pin: ghcr.io/techaroq/anubis:v1.13.0 was source-verified before # pinning (policy parser is JSON-only at this tag, flags are the config # surface via flagenv: an env var named TARGET sets --target, POLICY_FNAME # sets --policy-fname). Upgrading = stop unit, change Image=, deploy; policy # schema must be re-verified against the new tag first. # # No secrets here: Anubis holds no credentials (memory store; challenge # cookies are client-side JWTs). A restart invalidates issued challenges — # users just re-challenge once. See serverAppConfigs-docs/Infrastructure/Anubis.md. [Unit] Description=Anubis bot-challenge proxy container After=network-online.target Wants=network-online.target [Container] ContainerName=anubis Image=ghcr.io/techaroq/anubis:v1.13.0 Pull=never Network=dankclaw_default # flagenv maps env names to flag names (TARGET -> --target, POLICY_FNAME -> # --policy-fname). TARGET points back at Caddy's internal listener; the # container DNS name resolves on dankclaw_default. Environment=TARGET=http://caddy:8016 Environment=POLICY_FNAME=/policy/policy.json Volume=/home/dank/serverAppConfigs/dankclaw/anubis/policy.json:/policy/policy.json:ro # No HealthCmd: the image ships an exec-form HEALTHCHECK # (["/app/bin/anubis","--healthcheck"]) and quadlet inherits it when no # HealthCmd is set — this dodges the v1 generator's space-splitting quirk # that mangled quoted probes for the authentik units. [Service] Restart=always RestartSec=5 [Install] WantedBy=default.target