lila/documentation/ai-context/06-deployment.md
2026-05-16 01:59:43 +02:00

6.7 KiB
Raw Permalink Blame History

06 — Deployment

Purpose: Condensed infrastructure reference for LLMs working on deployment, CI/CD, or ops tasks. For full setup details (VPS provisioning, Forgejo configuration, backup scripts), see the human-readable DEPLOYMENT.md. Last updated: 2026-05-15 Depends on: 00-project-overview.md


Infrastructure Overview

Internet
     ↓
Caddy (Docker container, ports 80/443)
     ├── lilastudy.com       → web container (nginx:alpine, static files)
     ├── api.lilastudy.com   → api container (Express, port 3000)
     └── git.lilastudy.com   → forgejo container (git + registry, port 3000)

SSH (port 2222) → forgejo container (git push/pull)

VPS: Hetzner, Debian 13, ARM64 (aarch64), 4GB RAM
Domain: lilastudy.com, wildcard *.lilastudy.com configured
Only Caddy faces the internet. All other services communicate over internal Docker network.


Docker Compose Stack

Services on shared lila-network:

Service Image Ports (internal) Notes
caddy caddy:alpine 80, 443 Only container with published ports
api git.lilastudy.com/forgejo-lila/lila-api:latest 3000 Multi-stage Dockerfile, runs migrations on startup
web git.lilastudy.com/forgejo-lila/lila-web:latest 80 nginx:alpine, SPA fallback via try_files
database postgres:16 5432 Named volume lila-db for persistence
forgejo forgejo:... 3000, 2222 Git + container registry, SSH on 2222

No ports exposed on internal services. Only Caddy (80/443) and Forgejo SSH (2222) are public.


Build & Deploy Flow

Dev laptop: git push to main
     ↓
Forgejo Actions triggers (runner on VPS)
     ↓
Build API image (target: runner)
Build Web image (target: production, VITE_API_URL baked in)
     ↓
Push both to git.lilastudy.com registry
     ↓
SSH into VPS, docker compose pull, restart containers
     ↓
API container runs migrations on startup (migrate.js before server.js)
     ↓
App updated (~25 min total)

Cross-compilation: Images built natively on ARM64 VPS (no QEMU). Dev laptop used for initial pushes before CI/CD was set up.


Environment-Driven Config

Same code runs in dev and production. Environment variables control behavior:

Variable Dev Production
DATABASE_URL postgres://...@localhost:5432/lila postgres://...@database:5432/lila
BETTER_AUTH_URL http://localhost:3000 https://api.lilastudy.com
CORS_ORIGIN http://localhost:5173 https://lilastudy.com
COOKIE_DOMAIN undefined .lilastudy.com
VITE_API_URL http://localhost:3000 https://api.lilastudy.com (baked at build time)

Note: VITE_API_URL is baked into the frontend at Docker build time via --build-arg. It cannot be changed at runtime.


Database

Migrations

Drizzle migrations run automatically on API container startup. The Dockerfile entrypoint:

CMD ["node", "dist/src/migrate.js", "&&", "node", "dist/src/server.js"]

Deploy order enforced automatically: migrations before server starts.

Backups

  • Daily cron job at 3:00 AM: pg_dump → compressed SQL → ~/backups/
  • 7-day retention on VPS
  • Dev laptop auto-syncs new backups on login via rsync
  • Offsite storage: Planned (Hetzner Object Storage or S3-compatible)

Seeding

Idempotent (onConflictDoNothing). Safe to re-run for adding new languages without affecting existing data or user tables.


Auth & OAuth

Better Auth embedded in Express API. No separate auth service.

Social providers:

  • Google OAuth — consent screen in testing mode (100 user cap). Must publish before reaching 80 users.
  • GitHub OAuth — configured for both dev and production redirect URIs

Cross-subdomain cookies: COOKIE_DOMAIN=.lilastudy.com (leading dot) makes auth cookie valid across all subdomains.


Known Issues & Limitations

Issue Impact Status
lila-web has no healthcheck Vite dev server has no health endpoint; depends_on uses API healthcheck as proxy Acceptable for dev
Valkey memory overcommit warning Harmless in dev. Fix before production: vm.overcommit_memory = 1 Documented
No centralized monitoring/logging No uptime alerts or log aggregation on VPS Planned (BACKLOG.md)
Backups only on VPS + dev laptop No offsite protection against VPS failure Planned (BACKLOG.md)
Google OAuth in testing mode 100 user cap Must publish before 80 users

Key Files

File Purpose
docker-compose.yml (root) Local dev stack
docker-compose.yml (VPS) Production stack
apps/api/Dockerfile Multi-stage: deps → dev → builder → runner
apps/web/Dockerfile Multi-stage: deps → dev → builder → production (nginx)
apps/web/nginx.conf SPA fallback routing
Caddyfile Reverse proxy routing, automatic HTTPS
.forgejo/workflows/deploy.yml CI/CD pipeline
apps/api/src/migrate.ts Drizzle migration runner