# Updating PocketVeto — Remote Server Setup & Deployment Workflow How to push new code from your development machine and pull it on the production server. --- ## Overview The workflow is: ``` Local machine → git push → git.jackhlevy.com → (pull on server) → docker compose up --build -d ``` You develop locally, push to the Gitea remote, then update the production server — either manually over SSH or via an automated webhook. --- ## 1. SSH access to the production server Make sure you can SSH into the server without a password: ```bash # On your local machine — generate a key if you don't have one ssh-keygen -t ed25519 -C "pocketveto-deploy" # Copy the public key to the server ssh-copy-id user@YOUR_SERVER_IP ``` Test: ```bash ssh user@YOUR_SERVER_IP "echo ok" ``` --- ## 2. Server: clone the repo and authenticate On the server, clone from your Gitea instance: ```bash ssh user@YOUR_SERVER_IP cd /opt # or wherever you want to host it git clone https://git.jackhlevy.com/jack/civicstack.git cd civicstack ``` If your Gitea repo is private, create a **deploy token** in Gitea: - Gitea → Repository → Settings → Deploy Keys → Add Deploy Key (read-only is fine) - Or: Gitea → User Settings → Applications → Generate Token Store credentials so `git pull` doesn't prompt: ```bash # Using a personal access token stored in the URL git remote set-url origin https://YOUR_TOKEN@git.jackhlevy.com/jack/civicstack.git ``` Verify: ```bash git pull # should succeed with no password prompt ``` --- ## 3. Option A — Manual update (simplest) SSH in and run: ```bash ssh user@YOUR_SERVER_IP cd /opt/civicstack git pull origin main docker compose up --build -d ``` That's it. Docker rebuilds only the images that changed (layer cache means unchanged services rebuild in seconds). Migrations run automatically when the API container restarts. **One-liner from your local machine:** ```bash ssh user@YOUR_SERVER_IP "cd /opt/civicstack && git pull origin main && docker compose up --build -d" ``` --- ## 4. Option B — Deploy script Create `/opt/civicstack/deploy.sh` on the server: ```bash #!/bin/bash set -e cd /opt/civicstack echo "==> Pulling latest code" git pull origin main echo "==> Building and restarting containers" docker compose up --build -d echo "==> Done. Current status:" docker compose ps ``` ```bash chmod +x /opt/civicstack/deploy.sh ``` Now from your local machine: ```bash ssh user@YOUR_SERVER_IP /opt/civicstack/deploy.sh ``` --- ## 5. Option C — Automated webhook (Gitea → server) This triggers a deploy automatically every time you push to `main`. ### 5a. Create a webhook listener on the server Install a simple webhook runner. The easiest is [`webhook`](https://github.com/adnanh/webhook): ```bash apt install webhook ``` Create `/etc/webhook/hooks.json`: ```json [ { "id": "civicstack-deploy", "execute-command": "/opt/civicstack/deploy.sh", "command-working-directory": "/opt/civicstack", "response-message": "Deploying...", "trigger-rule": { "match": { "type": "payload-hmac-sha256", "secret": "your-webhook-secret", "parameter": { "source": "header", "name": "X-Gitea-Signature-256" } } } } ] ``` Start the webhook service: ```bash # Test it first webhook -hooks /etc/webhook/hooks.json -port 9000 -verbose # Or create a systemd service (recommended) ``` `/etc/systemd/system/webhook.service`: ```ini [Unit] Description=Webhook listener for civicstack deploys After=network.target [Service] ExecStart=/usr/bin/webhook -hooks /etc/webhook/hooks.json -port 9000 Restart=on-failure User=root [Install] WantedBy=multi-user.target ``` ```bash systemctl enable --now webhook ``` Expose port 9000 (or proxy it through nginx/Caddy at a path like `/hooks/`). ### 5b. Add the webhook in Gitea - Gitea → Repository → Settings → Webhooks → Add Webhook → Gitea - **Target URL:** `http://YOUR_SERVER_IP:9000/hooks/civicstack-deploy` - **Secret:** same value as `your-webhook-secret` above - **Trigger:** Push events → branch `main` Now every `git push origin main` automatically triggers a deploy. --- ## 6. Checking the deployed version After any update you can confirm what's running: ```bash # Check the git commit on the server ssh user@YOUR_SERVER_IP "cd /opt/civicstack && git log --oneline -3" # Check container status ssh user@YOUR_SERVER_IP "cd /opt/civicstack && docker compose ps" # Hit the health endpoint curl http://YOUR_SERVER_IP/api/health ``` --- ## 7. Rolling back If a bad deploy goes out: ```bash ssh user@YOUR_SERVER_IP cd /opt/civicstack # Roll back to the previous commit git revert HEAD --no-edit # preferred — creates a revert commit, keeps history clean # Or hard reset if you're sure (discards the bad commit locally — use with care) # git reset --hard HEAD~1 git push origin main # if using Option C, this triggers a new deploy automatically docker compose up --build -d # if manual ``` --- ## 8. Environment and secrets `.env` is **not** tracked in git. If you need to update a secret or add a new API key on the server: ```bash ssh user@YOUR_SERVER_IP nano /opt/civicstack/.env # Then restart only the affected services (usually api + worker) cd /opt/civicstack docker compose up -d --no-build api worker beat ``` `--no-build` skips the rebuild step — only a config reload is needed for env var changes. --- ## Summary | Goal | Command | |---|---| | Manual deploy | `ssh server "cd /opt/civicstack && git pull && docker compose up --build -d"` | | One-step deploy script | `ssh server /opt/civicstack/deploy.sh` | | Automated on push | Gitea webhook → webhook listener → `deploy.sh` | | Rollback | `git revert HEAD` + redeploy | | Update env only | Edit `.env` on server + `docker compose up -d --no-build api worker beat` | | Check what's running | `ssh server "cd /opt/civicstack && git log --oneline -1 && docker compose ps"` |