# MemPalace Caddy reverse-proxy config. # ----------------------------------------------------------------------------- # Listens on :8443 with a self-signed (Caddy-internal) cert. Enforces a # bearer-token check on every request and proxies authenticated traffic to # the mempalace container. # # Two upstream paths: # /sse, /messages* -> mempalace:8765 (mcp-proxy SSE for MCP tool calls) # /ingest* -> mempalace:8766 (in-process HTTP ingest endpoint) # /healthz -> mempalace:8766 (no auth, for liveness probes) # # Token comes from the MEMPAL_TOKEN env var (set in deploy/unraid/.env). # ----------------------------------------------------------------------------- { # Disable the admin API — never expose it from a container that's # reachable from clients. admin off # Ship access logs to stderr so `docker logs caddy` is useful. log { output stderr format console } } :8443 { tls internal # Liveness probe — no auth so Docker / external monitors can hit it # without holding the bearer token. handle /healthz { reverse_proxy mempalace:8766 } # Auth gate. matcher passes only when the Authorization header is # exactly `Bearer ${MEMPAL_TOKEN}`. Header matching is exact-match. @authorized header Authorization "Bearer {$MEMPAL_TOKEN}" # MCP-over-SSE: the MCP transport sends events on /sse and accepts # JSON-RPC POSTs on /messages (path varies by mcp-proxy version, so # proxy the whole prefix tree). handle @authorized { # SSE responses are streamed — disable buffering and force HTTP/1.1 # upstream to keep the event stream open. reverse_proxy /sse* /messages* mempalace:8765 { flush_interval -1 transport http { versions 1.1 } } reverse_proxy /ingest* mempalace:8766 } # Default: anything not matched above (or unauthenticated traffic) is # rejected. Returning 401 instead of 403 is correct here — clients with # no/invalid token can re-attempt with credentials. respond 401 { body "Unauthorized" close } }