# =============================================================================
# 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
#         }
#     }
# }
