Project_Manager/VPS_DEPLOY.md
2026-06-26 19:42:21 +02:00

338 lines
7.7 KiB
Markdown

# VPS_DEPLOY.md — Projekt-Hub auf dem VPS deployen (Docker + Caddy)
Deployment-Anleitung für den IONOS VPS (Debian 13, `patsy`, Docker + Caddy).
Diese Anleitung ersetzt `DEPLOYMENT.md` für diesen Server.
**Zielarchitektur:**
```
Internet → Caddy (Port 80/443, TLS automatisch) → projekt-hub:8000 (Docker) → SQLite (Volume)
```
**Voraussetzungen:**
- SSH-Zugang als `patsy` funktioniert
- Docker und die `proxy`-Netzwerk-Infrastruktur laufen (`caddy` + `proxy`-Netz)
- Code ist im lokalen Repo fertig und committed
---
## 1. Code auf den Server bringen
### Option A: Über Forgejo (git.bujour.de) — empfohlen
Zuerst lokal ins Forgejo pushen:
```bash
# Einmalig: Remote hinzufügen (falls noch nicht geschehen)
git remote add forgejo ssh://git@git.bujour.de:2222/patsy/projekt-hub.git
git push forgejo main
```
Dann auf dem VPS:
```bash
ssh patsy@<SERVER-IP>
mkdir -p ~/apps
git clone ssh://git@git.bujour.de:2222/patsy/projekt-hub.git ~/apps/projekt-hub
```
### Option B: Dateien direkt hochladen
```bash
# Lokal ausführen:
scp -r /pfad/zum/projekt-hub patsy@<SERVER-IP>:~/apps/projekt-hub
```
---
## 2. Docker-Image bauen
```bash
cd ~/apps/projekt-hub
docker build -t projekt-hub:latest .
```
Dauert beim ersten Mal ~2 Minuten (Dependencies werden heruntergeladen und gecacht).
Danach prüfen, dass das Image existiert:
```bash
docker images | grep projekt-hub
```
---
## 3. Verzeichnisse anlegen
```bash
mkdir -p ~/apps/projekt-hub/instance
mkdir -p ~/stacks/projekt-hub
```
---
## 4. `.env`-Datei anlegen
```bash
nano ~/apps/projekt-hub/.env
```
Inhalt (Werte anpassen):
```ini
FLASK_ENV=production
SECRET_KEY=<langer-zufaelliger-string>
# Datenbank (relative sqlite-Namen werden in instance/ aufgelöst)
DATABASE_URL=sqlite:///hub.sqlite
# Auth — nur diese E-Mail darf sich einloggen
ALLOWED_EMAILS=deine@adresse.com
# Login-Code-Einstellungen
LOGIN_CODE_TTL_MINUTES=10
LOGIN_CODE_RATE_LIMIT=5 per hour
# Rate-Limiting: memory:// reicht für Einzelnutzer / einen Worker
RATELIMIT_STORAGE_URI=memory://
# SMTP (siehe Abschnitt 7)
MAIL_SERVER=smtp.infomaniak.com
MAIL_PORT=587
MAIL_USE_TLS=true
MAIL_USE_SSL=false
MAIL_USERNAME=deine@adresse.com
MAIL_PASSWORD=<smtp-passwort>
MAIL_DEFAULT_SENDER=deine@adresse.com
# Cookies: Secure-Flag (HTTPS läuft über Caddy)
SESSION_COOKIE_SECURE=true
# SERVER_NAME leer lassen — Caddy übernimmt die Domain
SERVER_NAME=
```
Secret Key generieren:
```bash
python3 -c "import secrets; print(secrets.token_hex(32))"
```
Datei absichern:
```bash
chmod 600 ~/apps/projekt-hub/.env
```
---
## 5. Datenbank initialisieren
Die Migration einmalig in einem kurzlebigen Container ausführen:
```bash
docker run --rm \
--env-file /home/patsy/apps/projekt-hub/.env \
-v /home/patsy/apps/projekt-hub/instance:/app/instance \
projekt-hub:latest \
flask db upgrade
```
Prüfen, dass die SQLite-Datei angelegt wurde:
```bash
ls -lh ~/apps/projekt-hub/instance/
# → hub.sqlite sollte erscheinen
```
---
## 6. Compose-Stack einrichten und starten
`compose.yaml` aus dem Repo-Template kopieren:
```bash
cp ~/apps/projekt-hub/deploy/compose.yaml ~/stacks/projekt-hub/compose.yaml
```
Stack starten:
```bash
cd ~/stacks/projekt-hub
docker compose up -d
```
Container-Log prüfen (sollte "Listening at: http://0.0.0.0:8000" zeigen):
```bash
docker logs projekt-hub
```
---
## 7. Caddy konfigurieren
Einen Block zur Caddyfile hinzufügen:
```bash
nano ~/stacks/caddy/Caddyfile
```
Block anfügen (Subdomain nach Wunsch wählen, z.B. `hub.bujour.de`):
```
hub.bujour.de {
reverse_proxy projekt-hub:8000
}
```
Caddy neu laden — kein Neustart nötig, Caddy fetcht das TLS-Zertifikat automatisch:
```bash
docker exec caddy caddy reload --config /etc/caddy/Caddyfile
```
Im Browser `https://hub.bujour.de` öffnen — die Login-Seite sollte erscheinen.
> **DNS:** Der A-Record `hub.bujour.de → <SERVER-IP>` muss im DNS-Provider gesetzt sein,
> bevor Caddy das Zertifikat holen kann. Vorher ist die App nur intern erreichbar.
---
## 8. E-Mail-Versand einrichten
### Empfehlung: externer EU-SMTP-Relay (Infomaniak, Mailjet EU)
Am einfachsten und zuverlässigsten für Docker: ein externer SMTP-Anbieter.
SMTP-Zugangsdaten im Anbieter-Konto anlegen und in `.env` eintragen (Abschnitt 4).
Am Flask-Code ändert sich nichts — die App liest alles aus der Umgebung.
Testmail aus einem kurzlebigen Container:
```bash
docker run --rm \
--env-file /home/patsy/apps/projekt-hub/.env \
projekt-hub:latest \
python3 -c "
from dotenv import load_dotenv
from app import create_app
from app.extensions import mail
from flask_mail import Message
app = create_app('production')
with app.app_context():
msg = Message('Testmail Projekt-Hub', recipients=['deine@adresse.com'])
msg.body = 'Mailversand funktioniert.'
mail.send(msg)
print('Mail verschickt.')
"
```
### Alternative: Proton Bridge in Docker
Falls Proton Mail Bridge gewünscht: als eigenen Stack deployen und
`MAIL_SERVER=proton-bridge` in `.env` setzen (Container-Name als Hostname).
Proton Bridge muss im selben Docker-Netzwerk oder einem gemeinsamen Netzwerk laufen.
Details: `DEPLOYMENT.md §7` (Vorsicht: `127.0.0.1` funktioniert in Docker-Containern
**nicht** als SMTP-Adresse — immer Container-Name oder externe IP verwenden).
---
## 9. Abschluss-Test: Login-Flow
1. `https://hub.bujour.de` öffnen
2. E-Mail-Adresse aus `ALLOWED_EMAILS` eingeben und absenden
3. Postfach prüfen — 6-stelliger Code sollte innerhalb weniger Sekunden ankommen
4. Code auf der Verify-Seite eingeben
5. Weiterleitung zur Projektübersicht → fertig
---
## 10. Sicherheits-Checkliste
- [ ] `.env` hat restriktive Rechte: `chmod 600 ~/apps/projekt-hub/.env`
- [ ] `FLASK_ENV=production` und `SECRET_KEY` sind gesetzt (kein Default)
- [ ] `SESSION_COOKIE_SECURE=true` ist gesetzt (HTTPS läuft via Caddy)
- [ ] UFW: Ports 22, 80, 443 offen — **kein** direkter Zugriff auf Port 8000 von außen
- [ ] IONOS-Hardware-Firewall ebenfalls prüfen (nur 22, 80, 443 erlaubt)
- [ ] `.env` ist in `.gitignore` — niemals committen
UFW-Status prüfen:
```bash
sudo ufw status
```
Port 8000 ist nur intern (Docker `proxy`-Netz) erreichbar — das ist korrekt und gewollt.
---
## 11. Updates einspielen
```bash
cd ~/apps/projekt-hub
git pull
# Image neu bauen
docker build -t projekt-hub:latest .
# Migrationen (falls neue vorhanden)
docker run --rm \
--env-file /home/patsy/apps/projekt-hub/.env \
-v /home/patsy/apps/projekt-hub/instance:/app/instance \
projekt-hub:latest \
flask db upgrade
# Container neu starten
cd ~/stacks/projekt-hub
docker compose up -d --force-recreate
```
---
## 12. Backup
Die gesamte App-Datenbank ist eine einzelne SQLite-Datei. Tägliches Backup per Cronjob:
```bash
crontab -e
```
Zeile hinzufügen:
```
0 3 * * * sqlite3 /home/patsy/apps/projekt-hub/instance/hub.sqlite ".backup '/home/patsy/backups/hub-$(date +\%F).sqlite'" && find /home/patsy/backups -name "hub-*.sqlite" -mtime +30 -delete
```
Backup-Verzeichnis anlegen:
```bash
mkdir -p ~/backups
```
`sqlite3 .backup` ist konsistenter als einfaches `cp` bei laufender App.
---
## Anhang: Häufige Befehle
```bash
# Logs ansehen
docker logs -f projekt-hub
# Container neu starten
docker compose -f ~/stacks/projekt-hub/compose.yaml restart
# Container stoppen / starten
docker compose -f ~/stacks/projekt-hub/compose.yaml down
docker compose -f ~/stacks/projekt-hub/compose.yaml up -d
# Image neu bauen und Container ersetzen
cd ~/apps/projekt-hub && docker build -t projekt-hub:latest . && \
cd ~/stacks/projekt-hub && docker compose up -d --force-recreate
# Flask-Shell für Debugging
docker run --rm -it \
--env-file /home/patsy/apps/projekt-hub/.env \
-v /home/patsy/apps/projekt-hub/instance:/app/instance \
projekt-hub:latest \
flask shell
```