Preauth sits between Caddy and your web services to add an extra layer of authentication — because sometimes you want both a belt and suspenders.
Someone visits your protected service. Caddy intercepts the request and checks with preauth first.
If the user's preauth cookie is missing, invalid, or expired, they are shown a simple TOTP login screen.
After entering the correct 6-digit TOTP code, they receive a secure cookie and are forwarded to the service.
Single container deployment with persistent volumes for config and data.
Built to work seamlessly with Caddy's forward_auth directive.
Uses standard time-based one-time passwords — works with any authenticator app.
Optional subdomain-based single sign-on across multiple services.
Built-in login rate limiting to protect against brute force attacks.
Adjust colors, labels, and messages to match your branding.
You need three things: Docker, Caddy, and a web service to protect. Here's how to wire them together.
Copy example.env to .env and configure your TOTP secret. The app can generate one for you on first run — just be sure to save it.
# Required: TOTP URI (or leave blank to auto-generate)
TOTP_URI='otpauth://totp/MyService?secret=YOURSECRET'
# Optional: cookie lifetime (default 30 days)
COOKIE_TTL=2592000
# Optional: central auth across subdomains
SUBDOMAIN_REDIRECT=false
AUTH_SUBDOMAIN=''
# Optional: IP-based bypass for cookie-less systems
IP_TTL=0
# Optional: styling
TITLE='Pre-Authentication System'
BG_COLOR='#029386'
FG_COLOR='#ffffff'
Use the provided Docker Compose file to spin up preauth.
services:
preauth:
env_file:
- .env
expose:
- 80
image: digitaladapt/preauth:latest
restart: unless-stopped
volumes:
- preauth-config:/config
- preauth-data:/data
volumes:
preauth-config:
preauth-data:
Add a forward_auth block to your Caddyfile for any service you want to protect.
# Protect an entire service
service.example.com {
forward_auth preauth {
uri {uri}
copy_headers Remote-User
}
reverse_proxy service-container:80
}
# Or protect only specific paths
protected.example.com {
forward_auth /secure/* preauth {
uri {uri}
copy_headers Remote-User
}
reverse_proxy protected-service:9000
}
It's a good idea to generate single-use backup codes in case you lose access to your authenticator app.
docker exec -t preauth bin/console app:generate-backup-codes 10