# Deployment Guide ## Overview The MVP deployment target is a **Portainer-managed Docker Compose stack** with **Traefik** as the reverse proxy. All services run in Docker containers with automatic TLS via Let's Encrypt. ## Architecture ``` Internet | v Traefik (443/80) ──► Let's Encrypt TLS | ├──► api.example.com ──► FastAPI backend ├──► example.com ──► React frontend ├──► traefik.example.com ──► Traefik dashboard └──► {tool}-{project}-{user}.tools.example.com ──► Spawned tool containers ``` ## Prerequisites - Docker and Docker Compose - A domain with DNS A/AAAA records pointing to your server - Ports 80 and 443 open ## Quick Start ### 1. Configure Environment Copy the production environment example and fill in all values: ```bash cp deploy/.env.example deploy/.env ``` Required variables: | Variable | Description | Example | |----------|-------------|---------| | `ROOT_DOMAIN` | Your domain | `example.com` | | `ACME_EMAIL` | Let's Encrypt contact email | `admin@example.com` | | `POSTGRES_PASSWORD` | Database password | (strong random) | | `AUTHENTIK_CLIENT_SECRET` | OIDC client secret | (from Authentik) | | `SECRET_ENCRYPTION_KEY` | Fernet encryption key | (32-byte base64) | ### 2. Deploy Locally (Testing) ```bash docker compose -f docker-compose.prod.yml up --build -d ``` This starts: Traefik, API, web frontend, and PostgreSQL. ### 3. Deploy to Production (Portainer) 1. In Portainer, create a new stack 2. Upload `deploy/portainer-stack.yml` 3. Set environment variables from `deploy/portainer.env.example` 4. Deploy the stack ## Deployment Files | File | Purpose | |------|---------| | `docker-compose.yml` | Local development (API, web, Postgres) | | `docker-compose.prod.yml` | Production compose with Traefik | | `deploy/portainer-stack.yml` | Portainer stack definition | | `deploy/portainer.env.example` | Portainer environment variables | | `deploy/.env.example` | Production environment variables | ## Traefik Configuration Traefik handles all routing and TLS: - **Entrypoints**: `web` (80) → redirects to `websecure` (443) - **Certificates**: Let's Encrypt via TLS challenge - **Dashboard**: Available at `traefik.${ROOT_DOMAIN}` (protected by middleware) - **Metrics**: Prometheus metrics exposed on `/metrics` ### Subdomain Routing Tool containers are routed via subdomains: ``` {tool}-{project}-{user}.tools.{ROOT_DOMAIN} ``` Example: `vscode-myproject-john.tools.example.com` ## DNS Requirements Create DNS A records for: - `example.com` → your server IP - `*.example.com` → your server IP (wildcard for subdomains) - `*.tools.example.com` → your server IP (tool subdomains) ## Security - All services communicate over HTTPS - Traefik adds security headers (HSTS, XSS protection, etc.) - Database is not exposed externally - Secrets are injected via environment variables ## Updating To update the deployment: ```bash # Pull new images docker compose -f docker-compose.prod.yml pull # Restart services docker compose -f docker-compose.prod.yml up -d ``` ## Troubleshooting Check Traefik logs: ```bash docker logs traefik ``` Check service health: ```bash docker compose -f docker-compose.prod.yml ps ``` Verify certificates: ```bash curl -v https://api.example.com ```