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
204 lines
8.0 KiB
Caddyfile
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
|
|
# }
|
|
# }
|
|
# }
|