# Deployment Guide This project uses Gitea Actions for CI/CD, building a Docker image and deploying to a VPN-reachable VPS over SSH. ## Overview Deployment workflow: 1. **CI** (`.gitea/workflows/ci.yaml`): lint, test, type-check on every push 2. **Build and Deploy** (`.gitea/workflows/deploy.yaml`): build and deploy on `main` after CI succeeds, or manually via workflow dispatch --- ## 1. Prerequisites ### VPS Requirements - 2 vCPU, 2 GB RAM, 20 GB SSD - Docker Engine + Compose plugin - SSH access via VPN - Python 3.11+ (for healthcheck script) ### Gitea Instance Setup 1. Enable Actions in Gitea admin settings 2. Enable Actions for the repository 3. Register an Actions runner ### Runner Setup Gitea Actions uses `act_runner`. For Docker-based builds, ensure the runner host has: - Docker installed and accessible - `docker` and `docker compose` commands available Example runner registration: ```bash # On the runner host ./act_runner register --no-interactive --instance http://tea.uncloud.vpn --token ./act_runner daemon ``` Repository, organization, and instance runner tokens can be created from the Gitea web UI under Actions runner settings. --- ## 2. Required Secrets Configure in **Settings → Secrets and variables → Actions**. ### Secrets | Secret | Description | |--------|-------------| | `DEPLOY_SSH_PRIVATE_KEY` | SSH key for VPS access | | `REGISTRY_PASSWORD` | Container registry token (if needed) | | `DOCKERHUB_TOKEN` | Docker Hub token | | `TURNSTILE_SECRET_KEY` | Turnstile secret key | | `DATABENTO_API_KEY` | Databento API key | ### Variables | Variable | Description | |----------|-------------| | `DEPLOY_HOST` | VPS IP/hostname (VPN-reachable) | | `DEPLOY_USER` | Deploy user (default: `deploy`) | | `DEPLOY_PORT` | SSH port (default: `22`) | | `DEPLOY_PATH` | Deploy path (default: `/opt/vault-dash`) | | `REGISTRY` | Container registry URL | | `DOCKERHUB_USERNAME` | Docker Hub username | | `TURNSTILE_SITE_KEY` | Turnstile site key | --- ## 3. One-Time VPS Setup ```bash # Create deploy user sudo useradd -m -s /bin/bash deploy sudo usermod -aG docker deploy # Set up deployment directory sudo mkdir -p /opt/vault-dash sudo chown deploy:deploy /opt/vault-dash # Install Docker (Debian/Ubuntu) sudo apt-get update sudo apt-get install -y docker.io docker-compose-plugin # Add SSH key for deploy user sudo -u deploy mkdir -p /home/deploy/.ssh # Add public key to /home/deploy/.ssh/authorized_keys ``` --- ## 4. Local Development ```bash # Create virtual environment python -m venv .venv source .venv/bin/activate # Install dependencies pip install -r requirements.txt pip install -r requirements-dev.txt # Run tests pytest # Start development server uvicorn app.main:app --reload --port 8000 ``` ### Docker Development ```bash # Build and run docker-compose up --build # Access at http://localhost:8000 ``` --- ## 5. Manual Deployment ```bash # Set environment variables export DEPLOY_HOST="10.100.0.10" export DEPLOY_USER="deploy" export DEPLOY_SSH_PRIVATE_KEY="$(cat ~/.ssh/deploy_key)" export APP_IMAGE="registry.example.com/vault-dash:latest" # Run deploy script bash scripts/deploy-actions.sh ``` --- ## 6. VPN-Only Access The application binds to `127.0.0.1:8000` by default. Access via: 1. **VPN directly**: Connect VPN, access `http://VPS_IP:8000` 2. **Reverse proxy**: Use Caddy/Nginx on VPS for HTTPS ### Caddy Example ``` # Caddyfile vault.uncloud.vpn { reverse_proxy 127.0.0.1:8000 } ``` --- ## 7. Troubleshooting ### Runner can't build Docker images Ensure runner has Docker access: ```bash docker run --rm hello-world ``` ### SSH connection fails ```bash ssh -i ~/.ssh/deploy_key deploy@YOUR_VPS ``` Check firewall allows VPN traffic on port 22. ### Health check fails ```bash curl http://127.0.0.1:8000/health docker compose -f /opt/vault-dash/docker-compose.deploy.yml logs ``` ### Rollback ```bash cd /opt/vault-dash PREVIOUS=$(cat .last_successful_image) sed -i "s|^APP_IMAGE=.*|APP_IMAGE=$PREVIOUS|" .env docker compose -f docker-compose.deploy.yml up -d ```