caddy: add api.komistore.app vhost for paid-backend#22
Conversation
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.
|
No actionable comments were generated in the recent review. 🎉 ℹ️ Recent review info⚙️ Run configurationConfiguration used: defaults Review profile: CHILL Plan: Pro Run ID: 📒 Files selected for processing (1)
📝 WalkthroughWalkthroughA new Caddy vhost for ChangesPaid App Reverse Proxy
Estimated Code Review Effort🎯 2 (Simple) | ⏱️ ~12 minutes Poem
🚥 Pre-merge checks | ✅ 5✅ Passed checks (5 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing Touches🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
There was a problem hiding this comment.
Actionable comments posted: 2
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@Caddyfile.prod`:
- Around line 109-113: The CSP header defined by Content-Security-Policy
currently uses default-src 'self' which blocks inline <style> and <script> used
by the /legal pages; update the CSP string to explicitly allow inline styles and
scripts while keeping clickjacking protection—e.g., add script-src 'self'
'unsafe-inline' and style-src 'self' 'unsafe-inline' (or use nonces if you can
modify the pages) and keep frame-ancestors 'none' so the header in
Caddyfile.prod reads with explicit script-src and style-src allowing inline
content for the legal pages.
- Around line 94-103: In the api.komistore.app vhost block (the one containing
request_body and reverse_proxy paid-app:8080) add header hardening to prevent
forged forwarding headers: on the reverse_proxy to paid-app:8080 overwrite
X-Forwarded-For with the actual client IP (use Caddy's {remote}) and
remove/strip any incoming CF-Connecting-IP header before proxying (use header_up
to delete CF-Connecting-IP). This will ensure the reverse_proxy paid-app:8080
receives a trusted X-Forwarded-For and cannot be bypassed via CF-Connecting-IP.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
| # 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 <style>/<script> the legal | ||
| # pages use. Keep frame-ancestors locked down to prevent clickjack. | ||
| Content-Security-Policy "default-src 'self'; frame-ancestors 'none'" |
There was a problem hiding this comment.
CSP currently contradicts the inline legal-page requirement.
Line 111-Line 112 says /legal uses inline <style>/<script>, but default-src 'self' on Line 113 blocks inline content and can break those pages.
Proposed config adjustment
- Content-Security-Policy "default-src 'self'; frame-ancestors 'none'"
+ Content-Security-Policy "default-src 'self'; script-src 'self' 'unsafe-inline'; style-src 'self' 'unsafe-inline'; frame-ancestors 'none'"📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| # 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 <style>/<script> the legal | |
| # pages use. Keep frame-ancestors locked down to prevent clickjack. | |
| Content-Security-Policy "default-src 'self'; frame-ancestors 'none'" | |
| # 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 <style>/<script> the legal | |
| # pages use. Keep frame-ancestors locked down to prevent clickjack. | |
| Content-Security-Policy "default-src 'self'; script-src 'self' 'unsafe-inline'; style-src 'self' 'unsafe-inline'; frame-ancestors 'none'" |
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@Caddyfile.prod` around lines 109 - 113, The CSP header defined by
Content-Security-Policy currently uses default-src 'self' which blocks inline
<style> and <script> used by the /legal pages; update the CSP string to
explicitly allow inline styles and scripts while keeping clickjacking
protection—e.g., add script-src 'self' 'unsafe-inline' and style-src 'self'
'unsafe-inline' (or use nonces if you can modify the pages) and keep
frame-ancestors 'none' so the header in Caddyfile.prod reads with explicit
script-src and style-src allowing inline content for the legal pages.
Greptile SummaryThis PR adds a
Confidence Score: 5/5Safe to merge — the new vhost correctly replicates the direct-access security hardening from api-direct.github-store.org and introduces no regressions to the existing blocks. The change is a single Caddy vhost block that follows the established pattern documented in CLAUDE.md. Both previously flagged issues (XFF forgery and the CSP comment accuracy) are addressed in this revision. The XFF override and CF-Connecting-IP strip are in place, the 1 MB body cap is set, and the CSP comment explicitly notes the inline-asset constraint and that legal templates are kept inline-asset-free. No logic changes to the application, no migrations, no new code paths. No files require special attention. Important Files Changed
Sequence DiagramsequenceDiagram
participant Client
participant Caddy
participant paid-app
Client->>Caddy: HTTPS api.komistore.app (TLS, Let's Encrypt)
Note over Caddy: Override X-Forwarded-For → {remote_host}
Note over Caddy: Strip CF-Connecting-IP
Note over Caddy: Enforce 1 MB body cap
Caddy->>paid-app: HTTP paid-app:8080 (Docker network)
paid-app-->>Caddy: Response
Note over Caddy: Set security headers<br/>(CSP self, HSTS, XFO DENY, …)
Caddy-->>Client: HTTPS Response
Reviews (2): Last reviewed commit: "caddy: lock down api.komistore.app vhost..." | Re-trigger Greptile |
…g-IP strip, accurate CSP comment Direct-to-VPS path (grey-cloud DNS) was missing the X-Forwarded-For override and CF-Connecting-IP strip that api-direct.github-store.org already has — a client could forge XFF and rotate past paid-app's per-IP rate limiter, or claim any CF-Connecting-IP source. Both defences now match the established pattern. Also corrects the CSP comment: default-src 'self' does not permit inline <style>/<script> (those require 'unsafe-inline' in style-src/script-src or a nonce). The /legal templates are intentionally kept inline-asset-free so the directive holds.
Routes the new
api.komistore.apphostname at the paid-backend container (paid-app:8080on the shared Docker network). Same Caddy instance, same compose stack, distinct service name.DNS prerequisite
Before this lands,
api.komistore.appmust resolve to89.167.115.83. Otherwise Caddy will loop on ACME HTTP-01 (other vhosts unaffected, butdocker logs github-store-backend-caddy-1will scream).Cheapest setup: Cloudflare DNS →
A api.komistore.app → 89.167.115.83with the proxy OFF (grey-cloud). Caddy issues Let's Encrypt directly. Swap to proxied (orange-cloud) + Full(strict) later if traffic justifies fronting.What this fixes
Paid backend's container has been live since the last deploy (
Application -- Responding at http://0.0.0.0:8080) but unreachable from the internet because Caddyfile.prod had no vhost pointing at it. Adding the block letshttps://api.komistore.app/healthhit it.CSP note
Looser
default-src 'self'(vs the free-tier API's'none') because the paid backend serves/legalHTML pages alongside JSON.frame-ancestors 'none'stays locked.Post-merge
Auto-deploy fires → Caddy reload picks up the new block. Verify with:
curl -sS https://api.komistore.app/health # Expect: {"status":"ok"}Summary by CodeRabbit
New Features
Chores