You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
motief/thoughts/shared/plans/2026-03-26-motief-deploymen...

202 lines
4.7 KiB

# Deployment Plan: motief.sgeboers.nl
**Date:** 2026-03-26
**Subdomain:** `motief.sgeboers.nl`
**Stack:** Streamlit · DuckDB · Docker · Nginx · Drone CI
**Target:** VPS, `webapps` user at `/home/webapps/motief/`
---
## What's already ready (no changes needed)
- `Dockerfile` — builds `streamlit run Home.py --server.port=8501`
- `docker-compose.yml``motief` + `scheduler` services, `DATA_DIR` env override
- `.drone.yml` — builds image, pushes to registry, SSH-deploys on push to `main`
- `Home.py`, `pages/1_Stemwijzer.py`, `pages/2_Explorer.py` — all exist
---
## Step A — VPS: one-time directory setup
SSH in as `webapps`:
```bash
mkdir -p /home/webapps/motief/data
```
Create `/home/webapps/motief/.env`:
```env
DOCKER_REGISTRY=<your-registry-url>
DOCKER_USERNAME=<registry-user>
DOCKER_PASSWORD=<registry-password>
OPENROUTER_API_KEY=<key>
OPENAI_API_KEY=<key>
```
Copy `docker-compose.yml` into place:
```bash
# From local machine
scp docker-compose.yml webapps@<vps>:/home/webapps/motief/
```
Or just clone the repo there and symlink — either works since Drone will overwrite it.
---
## Step B — Transfer the database
From local machine (~4 GB, takes a few minutes):
```bash
rsync -avz --progress data/motions.db webapps@<vps>:/home/webapps/motief/data/motions.db
```
Do this as close to go-live as possible so the data isn't stale on launch.
---
## Step C — DNS
Add an **A record** in your DNS provider:
```
stematlas → (obsolete, skip)
motief → <VPS IPv4>
```
TTL 300 for the first deploy so you can iterate quickly; bump to 3600 after it's stable.
---
## Step D — Nginx vhost
Create `/etc/nginx/sites-available/motief`:
```nginx
server {
listen 80;
server_name motief.sgeboers.nl;
return 301 https://$host$request_uri;
}
server {
listen 443 ssl;
server_name motief.sgeboers.nl;
ssl_certificate /etc/letsencrypt/live/motief.sgeboers.nl/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/motief.sgeboers.nl/privkey.pem;
# Streamlit requires WebSocket upgrade for live updates
location / {
proxy_pass http://127.0.0.1:8501;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_read_timeout 86400;
}
}
```
Enable and reload:
```bash
sudo ln -s /etc/nginx/sites-available/motief /etc/nginx/sites-enabled/
sudo nginx -t && sudo systemctl reload nginx
```
---
## Step E — TLS cert
```bash
sudo certbot --nginx -d motief.sgeboers.nl
```
(Assumes Certbot is already installed and working for other subdomains.)
---
## Step F — Configure Drone secrets
In the Gitea/Drone repo settings for `sgeboers/stemwijzer`, add:
| Secret | Value |
|--------|-------|
| `DOCKER_REGISTRY` | Your registry URL |
| `DOCKER_USERNAME` | Registry login |
| `DOCKER_PASSWORD` | Registry password |
| `DEPLOY_HOST` | VPS hostname/IP |
| `DEPLOY_SSH_PORT` | SSH port (usually 22) |
| `DEPLOY_USER` | `webapps` |
| `DEPLOY_PASSWORD` | webapps SSH password |
---
## Step G — First deploy
Option 1 — trigger Drone automatically:
```bash
git push origin main
```
Drone builds → pushes image → SSH into VPS → `docker-compose up -d`.
Option 2 — manual first deploy (on VPS):
```bash
cd /home/webapps/motief
docker-compose pull
docker-compose up -d
```
---
## Step H — Verify
```bash
# On VPS
docker-compose -f /home/webapps/motief/docker-compose.yml logs -f motief
# From local browser
open https://motief.sgeboers.nl
```
Checklist:
- [ ] Home.py loads with nav to Stemwijzer and Explorer
- [ ] Compass tab renders with correct party positions (GL-PvdA top-left, PVV bottom-right)
- [ ] SVD tab scree plot shows with highlighted top-2 bars
- [ ] Similarity search returns results
- [ ] Scheduler container is running (`docker-compose ps`)
---
## Ongoing: data updates
The `scheduler` service runs the weekly pipeline inside the container:
- Scrapes new motions from the TK OData API
- Re-embeds new motion text via OpenRouter
- Updates similarity cache
The `motions.db` file on the VPS is the single source of truth — it's bind-mounted into both containers. No cron job needed on the host.
If you ever need to force a full re-run:
```bash
docker-compose exec scheduler python pipeline/run_pipeline.py --db-path data/motions.db
```
---
## Dependency order
```
A (dirs + .env) ─┐
B (rsync DB) ─┤─► G (first deploy) ─► H (verify)
C (DNS) ─┤
D (nginx) ─┤
E (certbot) ─┘
F (Drone secrets) ──► future auto-deploys on push to main
```
Steps A–F can all be done in one SSH session. Total estimated time: **45 minutes** (mostly waiting on rsync).