diff --git a/.env.example b/.env.example index 44c2e2c..6bdf939 100644 --- a/.env.example +++ b/.env.example @@ -4,6 +4,14 @@ # so they can be mounted into the container without env-var leakage. This # .env only holds non-secret tunables. +# --------------------------------------------------------------------------- +# Your root domain. This single value flows into authelia/configuration.yml +# (via Authelia's {{ env "DOMAIN" }} template substitution) and into +# caddy/Caddyfile (via Caddy's {env.DOMAIN} substitution). +# No manual find-and-replace needed -- just set this. +# --------------------------------------------------------------------------- +DOMAIN=example.com + # Pin your image versions. Bump to current stable when you upgrade -- # check https://github.com/authelia/authelia/releases and # https://github.com/crazy-max/docker-fail2ban/releases. diff --git a/README.md b/README.md index fead6fb..5ea91c1 100644 --- a/README.md +++ b/README.md @@ -209,15 +209,15 @@ openssl rand -hex 32 > authelia/secrets/SESSION_SECRET openssl rand -hex 32 > authelia/secrets/STORAGE_ENCRYPTION_KEY chmod 600 authelia/secrets/* -# 3) Copy and edit .env. +# 3) Copy and edit .env -- this is the only place you set your domain. +# DOMAIN flows into authelia/configuration.yml and caddy/Caddyfile +# automatically via each tool's env-var substitution; no find-and-replace. cp .env.example .env -$EDITOR .env # set TZ; pin AUTHELIA_VERSION if you want +$EDITOR .env # set DOMAIN, TZ; pin image versions if you want -# 4) Edit authelia/configuration.yml. -# Replace every `example.com` with your real root domain. -# Look for the four CHANGE comments: totp.issuer, session.cookies[].domain, -# session.cookies[].authelia_url, session.cookies[].default_redirection_url. -# Also uncomment access_control.rules entries for the sites you want to gate. +# 4) Uncomment access_control.rules in authelia/configuration.yml for the +# sites you want to gate. The domain is already templated -- just +# uncomment the right case block and choose one_factor or two_factor. $EDITOR authelia/configuration.yml # 5) Create your first user. @@ -254,11 +254,23 @@ Open `caddy/Caddyfile`. It defines: - `(authelia)` -- reusable snippet: add `import authelia` to any site block. - `(accesslog)` -- writes Caddy's JSON access log to `/var/log/caddy/access.log` so fail2ban's `caddy-4xx` jail can watch it. -- `auth.example.com` -- the Authelia portal. -- Example site blocks for all four cases (cases 1-3 active, case 4 commented). +- `auth.{env.DOMAIN}` -- the Authelia portal. +- Example site blocks for all four cases. -Copy the relevant blocks into your real Caddyfile, replace `example.com` with -your domain and `192.168.x.x` with real upstream IPs, then reload Caddy. +Copy the relevant blocks into your real Caddyfile and replace `192.168.x.x` +with real upstream IPs. The domain is already templated as `{env.DOMAIN}` -- +just make sure the `DOMAIN` environment variable is available to Caddy: + +```bash +# Dockerized Caddy -- add to its .env or compose environment: +DOMAIN=yourdomain.com + +# System Caddy -- add to /etc/caddy/caddy.env (or wherever systemd reads env): +echo 'DOMAIN=yourdomain.com' | sudo tee -a /etc/caddy/caddy.env +# Then make sure the systemd unit loads it: +# EnvironmentFile=/etc/caddy/caddy.env (in the [Service] section) +sudo systemctl daemon-reload && sudo systemctl reload caddy +``` **Every** site block should have `import accesslog` -- even case 4 sites. fail2ban's caddy-4xx jail watches the one log file and covers all your diff --git a/authelia/configuration.yml b/authelia/configuration.yml index 605ac5c..be37c6c 100644 --- a/authelia/configuration.yml +++ b/authelia/configuration.yml @@ -11,6 +11,10 @@ # Secrets are NOT in this file. They are loaded from files mounted at # /secrets via the AUTHELIA_*_FILE env vars in docker-compose.yml. # +# Your domain comes from the DOMAIN variable in .env -- no manual +# find-and-replace needed. Authelia 4.38+ processes this file as a Go +# template, so {{ env "DOMAIN" }} is substituted at startup. +# # After editing, validate before restarting: # docker compose run --rm authelia authelia validate-config --config /config/configuration.yml ############################################################################### @@ -37,7 +41,7 @@ identity_validation: totp: disable: false - issuer: 'example.com' # CHANGE: your root domain (shown in authenticator app) + issuer: '{{ env "DOMAIN" }}' # shown in your authenticator app algorithm: 'sha1' digits: 6 period: 30 @@ -75,8 +79,6 @@ authentication_backend: # --------------------------------------------------------------------------- # WHICH SITES NEED A RULE HERE? # -# There are four ways a site can relate to Authelia: -# # CASE 1 -- App has NO built-in auth (e.g. Pi doorbell PTT page). # -> Rule required + `import authelia` in Caddy. # -> Authelia is the ONLY login. Use two_factor for hardware-control pages. @@ -104,7 +106,7 @@ access_control: rules: # The Authelia portal itself is always bypass. - - domain: 'auth.example.com' # CHANGE + - domain: 'auth.{{ env "DOMAIN" }}' policy: 'bypass' # ------------------------------------------------------------------- @@ -112,24 +114,24 @@ access_control: # The Pi doorbell PTT page has no built-in authentication. # two_factor is appropriate -- this URL controls a speaker in your house. # ------------------------------------------------------------------- - # - domain: 'doorbell.example.com' # CHANGE + # - domain: 'doorbell.{{ env "DOMAIN" }}' # policy: 'two_factor' # ------------------------------------------------------------------- # CASE 2: App supports trusted-header proxy auth -- replace app login. - # Frigate 0.14+: set `auth.enabled: False` and configure `proxy:` in - # frigate_config/config.yml (see README.md "Switching Frigate to Authelia"). - # Single login: Authelia authenticates, Frigate reads Remote-User/Groups. + # Frigate: set auth.enabled: False and configure proxy: in + # frigate_config/config.yml (see README.md). Authelia handles login + # and passes Remote-User/Remote-Groups to Frigate for role mapping. # ------------------------------------------------------------------- - # - domain: 'cam.example.com' # CHANGE + # - domain: 'cam.{{ env "DOMAIN" }}' # policy: 'two_factor' # ------------------------------------------------------------------- # CASE 3: App keeps its own auth; Authelia adds a 2FA gate in front. - # The app's login form is still shown after Authelia passes the request. - # User logs into Authelia (2FA) then into the app separately. + # User authenticates with Authelia (2FA) then with the app itself. + # Add entries for any extra-gated domains here. # ------------------------------------------------------------------- - # - domain: 'nas.example.com' # CHANGE/REMOVE example + # - domain: 'nas.{{ env "DOMAIN" }}' # policy: 'two_factor' # CASE 4: No rule here, no `import authelia` in Caddy. App handles auth. @@ -138,9 +140,9 @@ session: # secret loaded via AUTHELIA_SESSION_SECRET_FILE cookies: - name: 'authelia_session' - domain: 'example.com' # CHANGE: your root domain - authelia_url: 'https://auth.example.com' # CHANGE - default_redirection_url: 'https://example.com' # CHANGE + domain: '{{ env "DOMAIN" }}' + authelia_url: 'https://auth.{{ env "DOMAIN" }}' + default_redirection_url: 'https://{{ env "DOMAIN" }}' expiration: '1 hour' inactivity: '5 minutes' remember_me: '1 month' diff --git a/caddy/Caddyfile b/caddy/Caddyfile index 9f72eed..8a3614a 100644 --- a/caddy/Caddyfile +++ b/caddy/Caddyfile @@ -2,7 +2,7 @@ # 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: +# your existing Caddyfile), then reload: # # # System Caddy: # sudo caddy validate --config /etc/caddy/Caddyfile @@ -11,9 +11,16 @@ # # 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 +# Domain is read from the DOMAIN environment variable -- no hardcoded +# domains in this file. Set it in your Caddy environment before reloading: +# +# # System Caddy (add to /etc/caddy/caddy.env or your systemd override): +# export DOMAIN=yourdomain.com +# +# # Dockerized Caddy (add to its .env or compose environment:): +# DOMAIN=yourdomain.com +# +# Only the upstream IPs need editing: replace 192.168.x.x with real LAN IPs. # # Requirements: # - Caddy v2.5.1+ (for `forward_auth` directive; tested on v2.11.2) @@ -90,38 +97,11 @@ # access_control.rules handles the portal itself. Adding forward_auth here # would cause a redirect loop. # ============================================================================= -auth.example.com { # CHANGE +auth.{env.DOMAIN} { 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. # @@ -147,11 +127,11 @@ auth.example.com { # CHANGE # # 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) +# Then uncomment the cam 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 +cam.{env.DOMAIN} { import accesslog import authelia @@ -165,6 +145,33 @@ cam.example.com { # CHANGE } } +# ============================================================================= +# 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 uncomment the doorbell rule in authelia/configuration.yml. +# ============================================================================= +# doorbell.{env.DOMAIN} { +# 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 { # CHANGE IP +# transport http { +# read_timeout 60s +# write_timeout 60s +# } +# } +# } +# +# handle { +# reverse_proxy 192.168.x.x:5555 # CHANGE IP +# } +# } + # ============================================================================= # CASE 3: App keeps its own login; Authelia adds a 2FA gate in front. # @@ -173,10 +180,10 @@ cam.example.com { # CHANGE # form appears. Two separate logins -- the app's auth is untouched. # # Also add a rule in authelia/configuration.yml: -# - domain: 'nas.example.com' +# - domain: 'nas.{{ env "DOMAIN" }}' # policy: 'two_factor' # ============================================================================= -# nas.example.com { # CHANGE/REMOVE example +# nas.{env.DOMAIN} { # CHANGE/REMOVE example # import accesslog # import authelia # @@ -193,7 +200,7 @@ cam.example.com { # CHANGE # 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 +# router.{env.DOMAIN} { # CHANGE/REMOVE example # import accesslog # reverse_proxy 192.168.x.x:PORT { # CHANGE # transport http { diff --git a/docker-compose.yml b/docker-compose.yml index 57e03cb..2a447ad 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -34,6 +34,9 @@ services: - AUTHELIA_SESSION_SECRET_FILE=/secrets/SESSION_SECRET - AUTHELIA_STORAGE_ENCRYPTION_KEY_FILE=/secrets/STORAGE_ENCRYPTION_KEY - TZ=${TZ:-UTC} + # Passed through so authelia/configuration.yml can use {{ env "DOMAIN" }} + # instead of hardcoding your domain in the config file. + - DOMAIN=${DOMAIN} volumes: - ./authelia:/config - ./authelia/secrets:/secrets:ro