505c9e8c0a655d826273eecb7182605af869986f
2
Commits
| Author | SHA1 | Message | Date | |
|---|---|---|---|---|
|
|
e1ac1da416 |
fix(deploy): reach storage over HTTP/1.1, and own storage CORS in the proxy
CI / verify (pull_request) Successful in 50s
CI / infrastructure-smoke (pull_request) Successful in 13s
CI / migration-smoke (pull_request) Successful in 1m47s
CI / image-build (pull_request) Successful in 18s
CI / deploy-smoke (same-origin) (pull_request) Successful in 47s
CI / deploy-smoke (split) (pull_request) Successful in 1m2s
Every reload of a cached files. image failed in the browser with ERR_HTTP2_PROTOCOL_ERROR. A browser revalidates a cached signed URL with If-None-Match. Caddy reached SeaweedFS over HTTP/2, and there SeaweedFS answers with a 304 declaring content-type: application/xml and content-length: 327 while sending no body. Caddy then logged "aborting with incomplete response ... unexpected EOF" and reset the stream. Over HTTP/1.1 SeaweedFS's 304 is clean. Measured layer by layer: DevTools, curl through Caddy, and curl direct over HTTP/1.1 and HTTP/2. The storage upstream is now HTTP/1.1 only (`versions 1.1`). Browsers still reach the proxy over HTTP/2 and HTTP/3. Delivery-layer CORS is the deployment's, so it no longer depends on which S3 backend is behind it. SeaweedFS's default reflected any origin and advertised PUT, POST and DELETE. Now the proxy: - grants CORS only to the origins that read objects with fetch(): the Ekklesia origin, or, when split, the API origin (displays) and the Dashboard origin (a module's preview caches images through fetch()); - allows GET and HEAD only, with Vary: Origin; - answers preflights itself, so they never reach storage; - strips the object store's own CORS headers. The deploy README documents the policy, its reasons, and what a self-run proxy must do. Co-Authored-By: Claude Opus 5.5 <[email protected]> |
||
|
|
167b4c4f14 |
feat(deploy): add the reference deployment Compose project
CI / verify (pull_request) Successful in 54s
CI / infrastructure-smoke (pull_request) Successful in 21s
CI / migration-smoke (pull_request) Successful in 1m48s
CI / image-build (pull_request) Successful in 27s
CI / deploy-smoke (pull_request) Successful in 42s
Implement ADR 0044's reference deployment as a base Compose file plus overlays, so an installation that already runs a proxy can use the base alone. - compose.yaml: api, postgres, object-storage, and the operator-only migrate (profile ops, plan by default). No published port. api and migrate run init, read-only, tmpfs /tmp, cap_drop ALL, no-new-privileges. postgres is only on the internal data network. - TLS everywhere from one installation-private CA: PostgreSQL TLS 1.3 only, with pg_hba rejecting every non-TLS connection, and the API on verify-full via EKKLESIA_DATABASE_CA (PEM text). SeaweedFS serves S3 over HTTPS (ADR 0030 requires https in production), trusted by the API through NODE_EXTRA_CA_CERTS. No Core change. - compose.proxy.yaml + Caddyfile.example: Caddy pinned by digest, ACME HTTP-01 (DNS-01 documented), routes /, /api/*, /display/*, /assets/* to api and refuses everything else; the storage hostname preserves Host. The API trusts exactly the proxy's fixed /32 on an edge network whose dynamic range excludes the fixed addresses; Caddy overwrites X-Forwarded-For and strips caller-supplied forwarding headers. - compose.tunnel.yaml: cloudflared pinned by digest, token from its own env file; Caddy honors CF-Connecting-IP only from its fixed address. - Four per-service root-owned env files, examples with no values; scripts/init-tls.sh (idempotent, never overwrites a key) and scripts/gen-secrets.sh (prints only). - CI: pnpm deploy:config in ci:verify for all three combinations, and a deploy-smoke job (scripts/smoke-deploy.sh) proving readiness, the Dashboard, signed storage delivery, the client-address chain, initial owner sign-in/out, verify-full database TLS, and Doctor through the proxy, against disposable services. tests/deploy.test.ts pins the structural guarantees. - ADR 0044 (still Proposed) amended to match: API-to-storage HTTPS, DNS-01 needs a custom Caddy build and tunnel-only needs DNS-01, the tunnel's origin TLS settings live in the Cloudflare dashboard, port 80 serves HTTP-01, and secrets are one env file per service. Co-Authored-By: Claude Opus 5.5 <[email protected]> |