# Production-ready Caddy config fronting both api and ui.
#
# Two-hostname pattern (recommended):
#     reputation.example.com       → ui   :8080
#     reputation-api.example.com   → api  :8081
#
# Caddy auto-provisions Let's Encrypt certs for both names. ACME HTTP-01
# requires port 80 to be reachable from the internet; ACME TLS-ALPN
# (default in Caddy 2) uses port 443.
#
# Replace the two hostnames with your own and put this file in
# /etc/caddy/Caddyfile (or `caddy run --config Caddyfile` for a manual
# deployment).
#
# If the api and ui run on the same host as Caddy, the upstream
# addresses below ("ui:8080" / "api:8081") work when Caddy joins the
# Docker network. If Caddy runs on the host, use 127.0.0.1:8080 /
# 127.0.0.1:8081 instead.

# ----- UI (humans in browsers) -----------------------------------
reputation.example.com {
    encode zstd gzip

    # Security headers — sensible defaults for an admin UI.
    header {
        Strict-Transport-Security "max-age=31536000; includeSubDomains"
        X-Frame-Options "DENY"
        X-Content-Type-Options "nosniff"
        Referrer-Policy "strict-origin-when-cross-origin"
        # Tailwind + Alpine + htmx + chart.js — relax `unsafe-inline`
        # if you tighten Tailwind to no inline styles. The current UI
        # ships a small inline `<head>` script for theme-before-paint
        # which needs `unsafe-inline` on script-src too.
        Content-Security-Policy "default-src 'self'; script-src 'self' 'unsafe-inline'; style-src 'self' 'unsafe-inline'; img-src 'self' data:; connect-src 'self'"
    }

    reverse_proxy ui:8080 {
        # Forward client info so the ui can log + audit accurately.
        header_up X-Forwarded-Proto {scheme}
        header_up X-Forwarded-Host {host}
        header_up X-Real-IP {remote}
    }
}

# ----- API (machine clients + ui server-to-server) ---------------
reputation-api.example.com {
    encode zstd gzip

    header {
        Strict-Transport-Security "max-age=31536000; includeSubDomains"
        X-Content-Type-Options "nosniff"
        # The api never frames anything; allowlist nothing.
        X-Frame-Options "DENY"
    }

    # /internal/* must NEVER traverse the public proxy. The api's own
    # Caddyfile inside the container blocks RFC1918-only paths, but
    # we belt-and-braces 404 it here so a misconfigured upstream
    # doesn't accidentally expose them.
    @internal {
        path /internal/*
    }
    handle @internal {
        respond 404
    }

    reverse_proxy api:8081 {
        header_up X-Forwarded-Proto {scheme}
        header_up X-Forwarded-Host {host}
        header_up X-Real-IP {remote}
    }
}

# ---- Single-hostname alternative --------------------------------
# If you don't want two hostnames, point everything at one and route
# by path prefix. Drop the two blocks above and use this one instead:
#
# reputation.example.com {
#     encode zstd gzip
#     @api path /api/* /healthz
#     handle @api {
#         reverse_proxy api:8081
#     }
#     handle {
#         reverse_proxy ui:8080
#     }
# }
#
# Caveat: future browser-direct frontends would then share an origin
# with the api, which simplifies CORS but couples deployment.
