# Add this to the Pi's existing Caddyfile. # # Caddy obtains and renews the certificate automatically, provided the VPS # forwards ports 80 and 443 through to this Caddy and the DNS name resolves to # the VPS's public address. # # The bearer-token check lives in the application, not here: Caddy would have # to be reloaded to rotate the token, whereas the app reads it from the # environment. Caddy's job is TLS, timeouts and keeping the container off the # public interface. mcp.example.org { encode zstd gzip # `schulcloud-mcp` is the Compose service name; Docker's embedded DNS # resolves it on the shared network. No host port is published. One proxy # serves both surfaces: /mcp for Claude and /api for the CLI. reverse_proxy schulcloud-mcp:8080 { # MCP's Streamable HTTP transport keeps a server-sent-events channel # open for server-initiated messages. Without flush_interval -1 Caddy # buffers those, and the connector appears to hang. flush_interval -1 # Long enough for a full re-crawl (~270 upstream requests) and for the # CLI streaming large files out of the mirror. transport http { read_timeout 600s write_timeout 600s } } header { Strict-Transport-Security "max-age=31536000; includeSubDomains" X-Content-Type-Options "nosniff" Referrer-Policy "no-referrer" -Server } log { output file /var/log/caddy/schulcloud-mcp.log format json # Request URLs are not secrets here (the token is in a header, not the # path), but the Authorization header must never be written to disk. # Caddy does not log headers by default; do not add them. } }