Skip to content

Add VPS deployment runbook and provisioning script - #224

Open
mnindrazaka wants to merge 1 commit into
feat/api-vpsfrom
claude/vps-api-deployment-phase-3-fuk7eb
Open

Add VPS deployment runbook and provisioning script#224
mnindrazaka wants to merge 1 commit into
feat/api-vpsfrom
claude/vps-api-deployment-phase-3-fuk7eb

Conversation

@mnindrazaka

Copy link
Copy Markdown
Collaborator

Summary

This PR adds comprehensive documentation and automation for provisioning and operating the VPS that runs apps/api in production. It includes an operational runbook, an idempotent provisioning script, and all necessary configuration templates for systemd, environment variables, firewall, and reverse proxy setup.

Key Changes

  • docs/runbook-vps-deployment.md: Complete operational reference covering:

    • Architecture overview (Caddy → API → MySQL)
    • First-time provisioning steps and verification
    • Secret rotation procedures
    • Logs and observability
    • Manual rollback procedures (until Phase 4 automation ships)
    • Database migration workflows with safety guidelines
    • Firewall and TLS configuration
  • deploy/vps/provision.sh: Idempotent, re-runnable provisioning script that:

    • Creates gatherloop (runtime) and deploy (CI) Unix users with appropriate permissions
    • Sets up /opt/gatherloop-api release directory structure
    • Installs and enables the systemd service unit
    • Configures sudoers with minimal privilege grants (only gatherloop-release and gatherloop-rollback)
    • Enables and configures ufw firewall (deny inbound except SSH/80/443)
    • Installs and configures Caddy for TLS termination
  • deploy/vps/systemd/gatherloop-api.service: Systemd unit with:

    • Runs as unprivileged gatherloop user
    • Loads secrets from /etc/gatherloop-api/api.env (readable only by root and gatherloop)
    • Restart-on-failure with 2s backoff
    • Hardened security settings (NoNewPrivileges, ProtectSystem, MemoryDenyWriteExecute, etc.)
  • deploy/vps/env/api.env.example: Template for application secrets (DB credentials, JWT secret, logging config)

  • deploy/vps/sudoers/gatherloop-deploy: Sudoers drop-in granting deploy user exactly two commands, both NOPASSWD

  • deploy/vps/caddy/Caddyfile.example: Reverse proxy template for TLS termination and proxying to 127.0.0.1:8000

Notable Implementation Details

  • Security model: The deploy user (SSH target for CI) owns the release directory but cannot read secrets. The gatherloop user runs the API and is the only user that can read /etc/gatherloop-api/api.env. A compromised deploy key grants code execution as an unprivileged user with no database credentials in reach.

  • Idempotent provisioning: The script safely re-runs after repo changes. It never overwrites existing secrets or customized Caddyfile, but will update managed files (systemd unit, sudoers, firewall rules) if the repo versions change.

  • Manual database migrations: By design, migrations are never run by the deploy pipeline. Operators run them by hand using the version-matched migrate binary shipped in each release, via systemd-run as the gatherloop user so credentials come from the env file.

  • Firewall isolation: Port 8000 (API's actual listen port) is unreachable from outside the box; only Caddy on the VPS can reach it, enforced by ufw.

https://claude.ai/code/session_01FkT3ro6MVgFZBuQZs5sNJ7

Adds infra-as-reviewed-text for the gatherloop-api VPS: an idempotent
provision.sh (users, filesystem layout, systemd unit, sudoers grant,
env template, ufw, Caddy), the systemd unit, sudoers drop-in, Caddyfile
and env file templates, and the operator runbook (provisioning, secret
rotation, logs, manual rollback, and the manual migration/seed
procedures). No CI deploy wiring and no production traffic change yet —
see docs/trd-vps-deployment-automation.md Phase 3.
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.

2 participants