- ROADMAP.md: mark all v0.9.8–v0.9.10 items shipped; Phase 4 accountability features complete; v1.0 criteria all met; update to reflect current state as of v0.9.10 - DEPLOYING.md: add SMTP/email section, ENCRYPTION_SECRET_KEY entry, fix OPENAI_MODEL default (gpt-4o → gpt-4o-mini), add pocketveto.org reference - UPDATING.md: replace personal git remote with YOUR_GIT_REMOTE placeholder for public deployability - ARCHITECTURE.md: add member_scores table, alignment API, LLM Batch API, email unsubscribe, bill tab UI, topic tags constant, Fernet encryption pattern, feature history through v0.9.10 Authored by: Jack Levy
254 lines
5.8 KiB
Markdown
254 lines
5.8 KiB
Markdown
# 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 → YOUR_GIT_REMOTE → (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://YOUR_GIT_REMOTE.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@YOUR_GIT_REMOTE.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"` |
|