163 lines
3.6 KiB
Markdown
163 lines
3.6 KiB
Markdown
# CheckPoint Ehrenamt — Deployment & Betrieb
|
|
|
|
> Flask/Gunicorn · Docker · cpe.bujour.info · Stand: Juni 2026
|
|
|
|
---
|
|
|
|
## Überblick
|
|
|
|
CheckPoint Ehrenamt läuft als Docker-Container auf dem EU-VPS hinter Caddy.
|
|
Das Image wird direkt auf dem VPS aus dem geklonten Forgejo-Repo gebaut —
|
|
kein Container-Registry, kein CI/CD.
|
|
|
|
**URL:** https://cpe.bujour.info
|
|
**Repo:** https://git.bujour.de/patsy/CP_EHRENAMT
|
|
**Code auf VPS:** `~/apps/checkpoint/`
|
|
**Stack:** `~/stacks/checkpoint/`
|
|
|
|
---
|
|
|
|
## Stack-Struktur
|
|
|
|
```
|
|
~/stacks/checkpoint/
|
|
├── compose.yaml
|
|
└── .env ← SECRET_KEY (nicht im Git)
|
|
|
|
~/apps/checkpoint/
|
|
├── Dockerfile
|
|
├── wsgi.py
|
|
├── gunicorn.conf.py
|
|
├── seed.py
|
|
├── requirements.txt
|
|
├── app/
|
|
└── instance/ ← DB + Uploads (Docker Volume)
|
|
```
|
|
|
|
---
|
|
|
|
## compose.yaml
|
|
|
|
```yaml
|
|
services:
|
|
checkpoint:
|
|
build: /home/patsy/apps/checkpoint
|
|
container_name: checkpoint
|
|
restart: unless-stopped
|
|
environment:
|
|
- CP_ENV=production
|
|
- SECRET_KEY=${SECRET_KEY}
|
|
volumes:
|
|
- checkpoint_data:/app/instance
|
|
networks:
|
|
- proxy
|
|
expose:
|
|
- "8000"
|
|
|
|
volumes:
|
|
checkpoint_data:
|
|
|
|
networks:
|
|
proxy:
|
|
external: true
|
|
```
|
|
|
|
---
|
|
|
|
## Erstes Deployment (Einmalig)
|
|
|
|
```bash
|
|
# 1. Repo klonen
|
|
git clone ssh://git@git.bujour.de:2222/patsy/CP_EHRENAMT.git ~/apps/checkpoint
|
|
|
|
# 2. Secret generieren
|
|
python3 -c "import secrets; print('SECRET_KEY=' + secrets.token_urlsafe(48))" \
|
|
> ~/stacks/checkpoint/.env
|
|
|
|
# 3. Image bauen und Container starten
|
|
cd ~/stacks/checkpoint
|
|
docker compose build
|
|
docker compose up -d
|
|
|
|
# 4. Datenbank seeden (einmalig)
|
|
docker exec checkpoint python seed.py
|
|
|
|
# 5. Ersten Admin anlegen (einmalig)
|
|
docker exec -e SECRET_KEY=$(grep SECRET_KEY ~/stacks/checkpoint/.env | cut -d= -f2) \
|
|
checkpoint flask --app wsgi create-admin <nutzername> "<anzeigename>" "<passwort>"
|
|
```
|
|
|
|
---
|
|
|
|
## Update einspielen
|
|
|
|
```bash
|
|
cd ~/apps/checkpoint
|
|
git pull
|
|
|
|
cd ~/stacks/checkpoint
|
|
docker compose build
|
|
docker compose up -d
|
|
```
|
|
|
|
Neue Tabellen werden beim Start automatisch via `db.create_all()` angelegt.
|
|
**Achtung:** Bestehende Tabellen werden nicht migriert — bei Schema-Änderungen
|
|
vorher Backup ziehen und ggf. manuell migrieren.
|
|
|
|
---
|
|
|
|
## Weitere Admins anlegen
|
|
|
|
```bash
|
|
docker exec -e SECRET_KEY=$(grep SECRET_KEY ~/stacks/checkpoint/.env | cut -d= -f2) \
|
|
checkpoint flask --app wsgi create-admin <nutzername> "<anzeigename>" "<passwort>"
|
|
```
|
|
|
|
---
|
|
|
|
## Datenbank-Backup (manuell)
|
|
|
|
```bash
|
|
docker exec checkpoint sqlite3 /app/instance/checkpoint.sqlite \
|
|
".backup '/app/instance/checkpoint-backup-$(date +%Y%m%d).sqlite'"
|
|
```
|
|
|
|
Das Backup liegt im Volume unter `/app/instance/` und kann von dort kopiert werden.
|
|
|
|
---
|
|
|
|
## Logs
|
|
|
|
```bash
|
|
# Live-Logs
|
|
docker logs checkpoint -f
|
|
|
|
# Letzte 100 Zeilen
|
|
docker logs checkpoint --tail 100
|
|
```
|
|
|
|
---
|
|
|
|
## Fehlersuche
|
|
|
|
| Problem | Ursache | Lösung |
|
|
|---|---|---|
|
|
| 500 nach Deploy | Fehlendes `SECRET_KEY` | `.env` prüfen, Container neu starten |
|
|
| Login funktioniert nicht | `CP_ENV` nicht gesetzt | `docker exec checkpoint env \| grep CP_ENV` |
|
|
| App nicht erreichbar | Caddy oder Container down | `docker ps`, dann Caddy-Reload |
|
|
| „database is locked" | Zu viele Worker für SQLite | `workers` in `gunicorn.conf.py` auf 2 senken |
|
|
|
|
---
|
|
|
|
## Technischer Stack
|
|
|
|
| Komponente | Entscheidung |
|
|
|---|---|
|
|
| Backend | Python 3.13 + Flask |
|
|
| WSGI | gunicorn (3 Worker, gthread) |
|
|
| Datenbank | SQLite mit WAL-Modus |
|
|
| Templating | Jinja2, server-rendered |
|
|
| CSS | Selbst gebaut, kein Framework |
|
|
| JavaScript | Minimal, Vanilla (nur Chat-Polling + Sidebar) |
|
|
| CSRF | Selbst gebaut (Session-Token, kein Flask-WTF) |
|
|
| Hosting | IONOS EU-VPS, Docker, Caddy (TLS automatisch) |
|