Skip to content

feat(deploy): Caddy HTTPS reverse proxy + live VPS bring-up + usage guide - #14

Merged
tomnguyen103 merged 3 commits into
mainfrom
feat/vps-caddy-https
Jun 2, 2026
Merged

feat(deploy): Caddy HTTPS reverse proxy + live VPS bring-up + usage guide#14
tomnguyen103 merged 3 commits into
mainfrom
feat/vps-caddy-https

Conversation

@tomnguyen103

@tomnguyen103 tomnguyen103 commented Jun 2, 2026

Copy link
Copy Markdown
Owner

Summary

Brings the production stack fully live on the single VPS and adds an operating guide.

  • Caddy reverse proxy (deploy/caddy/Caddyfile): single-origin HTTPS — /api/* → api, everything else → frontend; automatic Let's Encrypt cert via an <ip>.sslip.io host (no domain needed). HTTP→HTTPS redirect.
  • Fix Prometheus/Grafana ports: the VPS override's 127.0.0.1 binding concatenated with the base 0.0.0.0 binding (compose merges sequences), double-binding the port → "address already in use" left 4 services stuck in Created. Fixed with the compose !override tag (localhost-only).
  • Config hygiene: the box-specific docker-compose.vps.yml (carries the public host) is now git-ignored; a docker-compose.vps.yml.example template is committed instead (mirrors the .env.prod convention).
  • Docs: new docs/USAGE.md operating guide; live deploy recorded in PROGRESS.md + implementation-notes.md; deploy-checklist.md briefing cron corrected to use -p second-brain + both compose files.
  • Public IP scrubbed from all committed docs (YOUR_VPS_IP placeholder).

Verified

All 9 services up; end-to-end over HTTPS with a valid LE cert: /api/health, ingest→embed (Gemini)→search→cited gemini-2.5-flash chat, and a generated daily briefing.

🤖 Generated with Claude Code

Summary by CodeRabbit

  • New Features

    • Added HTTPS reverse-proxy and VPS-focused compose template to support single‑VPS production deployment.
  • Documentation

    • Expanded deployment, usage, runbooks, backup/restore, incident-response, implementation notes, progress log, and ADR entries for VPS live operation and gotchas.
  • Tests

    • Made CI apply step more resilient by retrying manifest application to handle transient admission webhook races.
  • Chores

    • Updated ignore rules to keep VPS-specific compose file out of commits.

- Caddy reverse proxy (deploy/caddy/Caddyfile): single-origin HTTPS, /api/* -> api,
  everything else -> frontend; automatic Let's Encrypt cert via <ip>.sslip.io (no domain).
- Fix prometheus/grafana localhost-only ports with compose !override (base + override
  port lists concatenate by default, causing a double-bind -> address-already-in-use that
  left 4 services stuck in Created).
- gitignore the box-specific docker-compose.vps.yml (carries the public host/IP); commit a
  docker-compose.vps.yml.example template instead, mirroring the .env.prod convention.
- docs/USAGE.md operating guide; record the live deploy in PROGRESS + implementation-notes;
  correct the deploy-checklist briefing cron to use -p second-brain + both compose files.
- scrub the public IP from all committed docs (YOUR_VPS_IP placeholder).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
@coderabbitai

coderabbitai Bot commented Jun 2, 2026

Copy link
Copy Markdown

Review Change Stack

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: 84511ead-80ae-434c-a7a3-3177eed070a8

📥 Commits

Reviewing files that changed from the base of the PR and between 538fbdb and 82336ca.

📒 Files selected for processing (3)
  • .github/workflows/k8s.yml
  • docs/PROGRESS.md
  • docs/implementation-notes.md

📝 Walkthrough

Walkthrough

This PR adds a Caddy HTTPS reverse-proxy, a VPS-specific docker-compose override example, updates compose invocation comments/env examples, and expands operational documentation and runbooks for running the full stack on a single VPS.

Changes

VPS Live Deployment: Caddy HTTPS, Docker Compose Override, and Operational Guide

Layer / File(s) Summary
Caddy HTTPS reverse-proxy configuration
deploy/caddy/Caddyfile, .gitignore
Caddy routes /api/* to the FastAPI backend (path stripped) and all other traffic to the Next.js frontend with automatic HTTPS and compression. .gitignore now excludes the non-example deploy/docker-compose.vps.yml.
Docker Compose VPS override template & compose docs
deploy/docker-compose.vps.yml.example, deploy/.env.prod.example, deploy/docker-compose.prod.yml
Adds a VPS override example that injects HTTPS API base URLs at build time, configures API CORS, forces prometheus/grafana to bind localhost via !override, provisions a public Caddy service (80/443) with mounted Caddyfile and persistent volumes, and updates compose header/comments and env example to reference the multi-file prod+vps invocation and -p second-brain.
Usage, implementation notes, and progress log
docs/USAGE.md, docs/implementation-notes.md, docs/PROGRESS.md
Provides live-operation guide, API endpoint docs, daily briefing ops, MCP tooling notes, and implementation notes covering Caddy+sslip.io routing and Compose override gotchas; PROGRESS.md records the 2026-06-02 VPS live deploy session.
Deploy runbooks and ADR update
docs/runbooks/deploy-checklist.md, docs/adr/0011-vps-provider.md
Standardizes deploy commands to use a DC helper (prod + vps compose files and -p second-brain), updates provisioning/provider choices and regions, corrects ADR owner location and Oracle region, and updates cron/rollback/update flows.
Backup/restore and incident-response runbooks
docs/runbooks/backup-restore.md, docs/runbooks/incident-response.md
Standardizes backup/restore and incident triage steps to use the DC helper variable, updates working directory and pg_restore/pg_dump commands, and replaces inline compose commands with $DC usage.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

Possibly related PRs

  • tomnguyen103/second-brain#11: Related k8s workflow changes that also apply/deploy deploy/k8s manifests in CI; shares context for the ingress webhook retry logic.

Poem

🐰 A rabbit hops across the VPS night,
Caddy hums and serves the HTTPS light,
Docker stacks in ordered rows,
Docs and runbooks help it grow,
Second Brain wakes — all systems bright.

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title accurately and specifically describes the main changes: Caddy HTTPS reverse proxy setup, live VPS deployment, and documentation for usage and operations.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch feat/vps-caddy-https

Comment @coderabbitai help to get the list of available commands and usage tips.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🤖 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 `@docs/runbooks/deploy-checklist.md`:
- Around line 10-11: The runbook's deploy command contract is inconsistent:
update the command blocks in Steps 4, 5, and 8 to use the canonical compose
invocation shown in the diff (include -p second-brain, both compose files
deploy/docker-compose.prod.yml and deploy/docker-compose.vps.yml, and --env-file
deploy/.env.prod) so they match the new contract and ensure VPS overrides are
applied; scan the document for any other occurrences of docker-compose.prod.yml
alone and replace them with the full canonical command to avoid recreating the
duplicate-project issue.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: 6f0b88c7-dca1-4fc3-b9a6-f2f2b6c71717

📥 Commits

Reviewing files that changed from the base of the PR and between 8bd2566 and 52ffa86.

⛔ Files ignored due to path filters (3)
  • docs/screenshots/ui-chat-answer.png is excluded by !**/*.png
  • docs/screenshots/ui-chat.png is excluded by !**/*.png
  • docs/screenshots/ui-home.png is excluded by !**/*.png
📒 Files selected for processing (8)
  • .gitignore
  • deploy/caddy/Caddyfile
  • deploy/docker-compose.vps.yml.example
  • docs/PROGRESS.md
  • docs/USAGE.md
  • docs/adr/0011-vps-provider.md
  • docs/implementation-notes.md
  • docs/runbooks/deploy-checklist.md

Comment thread docs/runbooks/deploy-checklist.md

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
deploy/docker-compose.vps.yml.example (1)

51-52: ⚠️ Potential issue | 🔴 Critical | ⚡ Quick win

Caddyfile volume mount path is incorrect for the documented invocation.

The volume mount ./caddy/Caddyfile is relative to the working directory. According to the header comment (line 5) and the deploy-checklist runbook, docker compose is invoked from the repository root with -f deploy/docker-compose.prod.yml -f deploy/docker-compose.vps.yml. From that context, ./caddy/Caddyfile would resolve to <repo-root>/caddy/Caddyfile, but the Caddyfile is actually located at deploy/caddy/Caddyfile (per the review stack context).

🔧 Proposed fix
     volumes:
-      - ./caddy/Caddyfile:/etc/caddy/Caddyfile:ro
+      - ./deploy/caddy/Caddyfile:/etc/caddy/Caddyfile:ro
       - caddy_data:/data
       - caddy_config:/config
🤖 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 `@deploy/docker-compose.vps.yml.example` around lines 51 - 52, The Caddyfile
volume mount in deploy/docker-compose.vps.yml.example is wrong for the
documented invocation: replace the relative path string "./caddy/Caddyfile" with
the repository-root-correct path "./deploy/caddy/Caddyfile" so the compose stack
(when run with -f deploy/docker-compose.prod.yml -f
deploy/docker-compose.vps.yml) mounts the actual Caddyfile; keep the existing
:ro flag intact.
🧹 Nitpick comments (1)
docs/runbooks/deploy-checklist.md (1)

81-81: 💤 Low value

Consider extracting the cron command to a wrapper script for maintainability.

The cron command is ~280 characters long and hardcodes the full docker compose invocation with both files, project name, and env file. While this works, any changes to the compose invocation pattern would require updating this cron line.

An alternative would be a small wrapper script /usr/local/bin/second-brain-enqueue-briefing that contains the docker compose command, making the cron line much shorter and the command easier to maintain.

However, the current approach is explicit and doesn't hide complexity, which is valuable for operational transparency. This is a trade-off decision.

Alternative wrapper script approach

Create /usr/local/bin/second-brain-enqueue-briefing:

#!/bin/bash
set -euo pipefail
cd /root/second-brain
docker compose -p second-brain \
  -f deploy/docker-compose.prod.yml \
  -f deploy/docker-compose.vps.yml \
  --env-file deploy/.env.prod \
  exec -T worker python -m app.jobs.enqueue briefing

Then simplify the cron line:

0 7 * * *  root  /usr/local/bin/second-brain-enqueue-briefing >> /var/log/second-brain-briefing.log 2>&1
🤖 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 `@docs/runbooks/deploy-checklist.md` at line 81, Extract the long cron
docker-compose invocation into a wrapper script named
second-brain-enqueue-briefing: create an executable script that sets strict
shell options (e.g., set -euo pipefail), cds to the repository, runs the same
docker compose invocation currently in the cron line (including the project
name, both compose files, env-file and the exec -T worker python -m
app.jobs.enqueue briefing invocation), and then replace the cron entry with a
shorter call to second-brain-enqueue-briefing that redirects stdout/stderr to
the existing log file; ensure the script is executable and owned appropriately.
🤖 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.

Outside diff comments:
In `@deploy/docker-compose.vps.yml.example`:
- Around line 51-52: The Caddyfile volume mount in
deploy/docker-compose.vps.yml.example is wrong for the documented invocation:
replace the relative path string "./caddy/Caddyfile" with the
repository-root-correct path "./deploy/caddy/Caddyfile" so the compose stack
(when run with -f deploy/docker-compose.prod.yml -f
deploy/docker-compose.vps.yml) mounts the actual Caddyfile; keep the existing
:ro flag intact.

---

Nitpick comments:
In `@docs/runbooks/deploy-checklist.md`:
- Line 81: Extract the long cron docker-compose invocation into a wrapper script
named second-brain-enqueue-briefing: create an executable script that sets
strict shell options (e.g., set -euo pipefail), cds to the repository, runs the
same docker compose invocation currently in the cron line (including the project
name, both compose files, env-file and the exec -T worker python -m
app.jobs.enqueue briefing invocation), and then replace the cron entry with a
shorter call to second-brain-enqueue-briefing that redirects stdout/stderr to
the existing log file; ensure the script is executable and owned appropriately.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: 95a34e96-77b8-4ac2-981f-875f880ad2f5

📥 Commits

Reviewing files that changed from the base of the PR and between 52ffa86 and 538fbdb.

📒 Files selected for processing (9)
  • deploy/.env.prod.example
  • deploy/docker-compose.prod.yml
  • deploy/docker-compose.vps.yml.example
  • docs/PROGRESS.md
  • docs/USAGE.md
  • docs/implementation-notes.md
  • docs/runbooks/backup-restore.md
  • docs/runbooks/deploy-checklist.md
  • docs/runbooks/incident-response.md
✅ Files skipped from review due to trivial changes (4)
  • deploy/docker-compose.prod.yml
  • deploy/.env.prod.example
  • docs/PROGRESS.md
  • docs/USAGE.md
🚧 Files skipped from review as they are similar to previous changes (1)
  • docs/implementation-notes.md

@tomnguyen103
tomnguyen103 merged commit fe994b6 into main Jun 2, 2026
9 checks passed
@tomnguyen103
tomnguyen103 deleted the feat/vps-caddy-https branch June 2, 2026 23:44
tomnguyen103 added a commit that referenced this pull request Jun 3, 2026
- status badges -> live / 7-of-7 / Caddy auto-HTTPS / eval-gated CI
- hero screenshot + live callout; new "What's New" (PRs #12/#13/#14/#16)
- tech stack: gemini-2.5-flash, dual embedding providers (both 384-dim),
  Caddy reverse proxy, PgBouncer
- production architecture diagram (9 services); reworked quickstart;
  new "Deploy to a VPS" -> docs/USAGE.md; updated layout + ADR links

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant