Files
frigate_w_audio/caddy/Caddyfile
T
Claude 1b4c9298e1 Update authelia stack: 4 auth cases, full Caddyfile, improved docs
Keeps this as a standalone authelia+fail2ban stack (no Frigate services).

Changes:
- docker-compose.yml: fail2ban depends_on authelia with service_healthy
  condition so authelia.log exists before fail2ban tries to bind-mount it;
  add inline note about pre-creating the log file
- authelia/configuration.yml: expand access_control comment block to cover
  all 4 cases (added Case 3: app keeps own auth + Authelia as 2FA gate,
  and Case 4: app handles auth alone); clearer per-case commented rules
- caddy/Caddyfile (replaces snippet.example.caddyfile): complete Caddyfile
  with all 4 auth-case examples; (accesslog) imported in every block so
  fail2ban caddy-4xx jail covers all subdomains, not just gated ones;
  full inline docs for enabling Frigate proxy auth
- README.md: expand "Which sites" from 3 to 4 cases; add proxy-auth service
  compatibility table (Frigate, Grafana, Gitea, Nextcloud, HA, Portainer
  etc.); clarify fail2ban covers all sites via single caddy-4xx jail;
  add touch authelia/authelia.log to first-run; add troubleshooting entries
  for authelia.log bind-mount directory bug and fail2ban chain verification

https://claude.ai/code/session_012eTokAaGiZo7aGt1T2W9BC
2026-04-26 02:46:42 +00:00

204 lines
8.0 KiB
Caddyfile

# =============================================================================
# Caddyfile -- Authelia + fail2ban integration
#
# Copy this file into your Caddy setup (or merge the relevant blocks into
# your existing Caddyfile), edit all placeholders, then reload:
#
# # System Caddy:
# sudo caddy validate --config /etc/caddy/Caddyfile
# sudo systemctl reload caddy
#
# # Dockerized Caddy:
# docker compose exec caddy caddy reload --config /etc/caddy/Caddyfile
#
# Placeholders to replace:
# example.com -> your real root domain
# 192.168.x.x -> real upstream LAN IPs
#
# Requirements:
# - Caddy v2.5.1+ (for `forward_auth` directive)
# - Caddy must be on the `caddy_net` Docker network so it can resolve
# `authelia` by container name. In your Caddy compose:
# networks: [caddy_net]
# and at the bottom:
# networks:
# caddy_net:
# external: true
#
# =============================================================================
# DECISION TREE -- which sites go behind Authelia?
#
# CASE 1 -- App has NO built-in auth (e.g. Pi doorbell PTT page).
# `import authelia` + rule in authelia/configuration.yml.
# Authelia is the ONLY login. Use two_factor for hardware-control pages.
#
# CASE 2 -- App has built-in auth AND supports trusted-header proxy auth
# (Frigate 0.14+, Grafana, Gitea, Nextcloud, Home Assistant, ...).
# `import authelia` + rule in Authelia + disable the app's own login form.
# Single Authelia login: Authelia authenticates, app reads Remote-User header.
#
# CASE 3 -- App has built-in auth and CANNOT switch to proxy auth, but you
# want a 2FA gate in front anyway (router admin, legacy apps, etc.).
# `import authelia` + rule in Authelia. App auth is untouched.
# User logs into Authelia (2FA), then the app's own login form appears.
#
# CASE 4 -- App handles its own auth; Authelia not involved.
# Plain `reverse_proxy`, no `import authelia`, no Authelia rule.
# Traffic skips Authelia entirely.
#
# fail2ban coverage: import (accesslog) in EVERY site block -- gated or not.
# The caddy-4xx jail watches /var/log/caddy/access.log and bans scanners
# spraying all your subdomains, not just the Authelia-gated ones.
# =============================================================================
# -----------------------------------------------------------------------------
# (authelia) -- forward_auth gate.
# Import into any site block you want gated (cases 1, 2, 3).
# On success Authelia sets Remote-User, Remote-Groups, Remote-Email,
# Remote-Name headers that the upstream app can consume for role mapping.
# -----------------------------------------------------------------------------
(authelia) {
forward_auth authelia:9091 {
uri /api/authz/forward-auth
copy_headers Remote-User Remote-Groups Remote-Email Remote-Name
}
}
# -----------------------------------------------------------------------------
# (accesslog) -- structured JSON access log consumed by fail2ban's caddy-4xx
# jail. Import into EVERY site block so fail2ban covers your whole stack.
#
# Pre-create the log directory before starting Caddy:
# sudo mkdir -p /var/log/caddy
# sudo chown caddy:caddy /var/log/caddy # system Caddy
# # Dockerized Caddy: add volumes: ["/var/log/caddy:/var/log/caddy"] to compose
# -----------------------------------------------------------------------------
(accesslog) {
log {
output file /var/log/caddy/access.log {
roll_size 10MiB
roll_keep 5
roll_keep_for 720h
}
format json
}
}
# =============================================================================
# Authelia login portal
# Never add `import authelia` here -- the `bypass` rule in
# access_control.rules handles the portal itself. Adding forward_auth here
# would cause a redirect loop.
# =============================================================================
auth.example.com { # CHANGE
import accesslog
reverse_proxy authelia:9091
}
# =============================================================================
# CASE 1: Pi doorbell PTT page -- Authelia is the ONLY auth.
#
# The Pi's Flask server has no built-in authentication. Authelia gates it.
# two_factor is appropriate -- this URL controls a speaker in your house.
# Comment out until the Pi is deployed.
# Also add (or uncomment) the doorbell.example.com rule in configuration.yml.
# =============================================================================
# doorbell.example.com { # CHANGE
# import accesslog
# import authelia
#
# # Same-origin proxy to Frigate so WebRTC fetch works without CORS.
# handle_path /frigate/* {
# reverse_proxy 192.168.x.x:8971 {
# transport http {
# read_timeout 60s
# write_timeout 60s
# }
# }
# }
#
# handle {
# reverse_proxy 192.168.x.x:5555
# }
# }
# =============================================================================
# CASE 2: Frigate UI -- Authelia replaces Frigate's own login form.
#
# Frigate 0.14+ supports trusted-header proxy auth. Authelia authenticates
# the user (optionally with TOTP 2FA), then passes Remote-User and
# Remote-Groups headers to Frigate which maps them to admin/viewer roles.
#
# To enable proxy auth in Frigate, edit frigate_config/config.yml:
#
# auth:
# enabled: False
# trusted_proxies:
# - 172.18.0.0/16 # caddy_net subnet; find it with:
# # docker network inspect caddy_net
# proxy:
# header_map:
# user: remote-user # matches copy_headers in (authelia) snippet
# role: remote-groups
# default_role: viewer
# separator: '|'
# # Optional shared secret -- prevents LAN header spoofing.
# # Generate: openssl rand -hex 32
# # Set the same value as header_up X-Proxy-Secret below.
# # auth_secret: 'your-32-byte-hex'
#
# Then uncomment the cam.example.com rule in authelia/configuration.yml
# and restart: docker compose restart authelia (in the authelia stack)
# docker compose restart frigate (in the camera stack)
# =============================================================================
cam.example.com { # CHANGE
import accesslog
import authelia
reverse_proxy 192.168.x.x:8971 { # CHANGE IP
transport http {
read_timeout 60s
write_timeout 60s
}
# Uncomment if you set auth_secret: in Frigate's proxy: block.
# header_up X-Proxy-Secret "your-32-byte-hex-here"
}
}
# =============================================================================
# CASE 3: App keeps its own login; Authelia adds a 2FA gate in front.
#
# Use when an app can't do proxy auth but you still want 2FA before it.
# The user authenticates with Authelia (2FA), then the app's own login
# form appears. Two separate logins -- the app's auth is untouched.
#
# Also add a rule in authelia/configuration.yml:
# - domain: 'nas.example.com'
# policy: 'two_factor'
# =============================================================================
# nas.example.com { # CHANGE/REMOVE example
# import accesslog
# import authelia
#
# reverse_proxy 192.168.x.x:PORT { # CHANGE
# transport http {
# tls_insecure_skip_verify # only if self-signed TLS
# }
# }
# }
# =============================================================================
# CASE 4: App handles its own auth; Authelia not involved.
#
# No `import authelia`. No access_control rule in Authelia.
# Still import accesslog so fail2ban's caddy-4xx jail covers this site.
# =============================================================================
# router.example.com { # CHANGE/REMOVE example
# import accesslog
# reverse_proxy 192.168.x.x:PORT { # CHANGE
# transport http {
# tls_insecure_skip_verify
# }
# }
# }