From 042b4d9f8a83f6068c0d6a8e6759a1731b0287d9 Mon Sep 17 00:00:00 2001 From: rainxchzed Date: Mon, 25 May 2026 07:04:22 +0500 Subject: [PATCH 1/2] caddy: add api.komistore.app vhost reverse-proxying to paid-app:8080 Routes the new komistore.app hostname at the paid-backend container. Reuses the same Caddy instance as the free-tier API; service names paid-app:8080 + app:8080 stay distinct on the Docker network. DNS prereq: api.komistore.app must resolve to the VPS IP for HTTP-01 challenge to succeed. Start with a DNS-only (grey-cloud) A record; switch to proxied + Full(strict) later once traffic justifies fronting. CSP is looser than the free-tier API block because the paid backend serves /legal HTML pages alongside JSON. frame-ancestors stays locked to 'none' to keep clickjack closed. --- Caddyfile.prod | 41 +++++++++++++++++++++++++++++++++++++++++ 1 file changed, 41 insertions(+) diff --git a/Caddyfile.prod b/Caddyfile.prod index 2b90894..7f5d875 100644 --- a/Caddyfile.prod +++ b/Caddyfile.prod @@ -78,3 +78,44 @@ api-direct.github-store.org { output stdout } } + +# Komi Store paid backend. Hosted on the same VPS, separate Docker service +# (paid-app), separate Postgres database (komistore_paid). Will eventually +# absorb the github-store.org hostnames above once the free-tier migration +# lands; for now the two run side-by-side under distinct vhosts so DNS, +# Stripe webhook URLs, and Cloudflare KV bindings stay decoupled. +# +# DNS prereq: api.komistore.app must resolve to this VPS for Caddy's +# HTTP-01 challenge to issue a Let's Encrypt cert. Either: +# (a) DNS-only (grey-cloud) A record -> VPS IP, OR +# (b) Cloudflare proxied + SSL mode "Full (strict)" + Cloudflare origin +# cert OR DNS-01 challenge configured in Caddy. +# Start with (a) until traffic justifies fronting. +api.komistore.app { + + # Body cap. Stripe webhooks can be ~10 KB; checkout payloads are tiny. + # 1 MB matches the free-tier ceiling -- bumps need a written reason. + request_body { + max_size 1MB + } + + reverse_proxy paid-app:8080 + + header { + -Server + X-Content-Type-Options nosniff + X-Frame-Options DENY + Strict-Transport-Security "max-age=63072000; includeSubDomains; preload" + # Looser than the API-only CSP above because the paid backend + # serves the /legal HTML pages (terms, privacy) as well as JSON. + # default-src 'none' would break inline