Bei COOKIE_SECURE=true und Zugriff über HTTP verwirft der Browser das Sitzungs-Cookie. Die Anmeldung selbst meldet Erfolg, die nächste Anfrage gilt aber als nicht angemeldet – der Nutzer landet ohne jede Meldung wieder auf der Anmeldemaske und hält es für ein falsches Passwort. - Das Frontend prüft die Sitzung unmittelbar nach der Anmeldung und nennt bei einem Fehlschlag die Ursache samt beider Auswege - Das Backend protokolliert dieselbe Kombination als Warnung und wertet dabei X-Forwarded-Proto aus, weil hinter einem Reverse Proxy immer http ankommt - docs/deployment.md beschreibt das Symptom wörtlich Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_014e7t8UpmoVNMtWivY5LiSH
258 lines
7.8 KiB
Markdown
258 lines
7.8 KiB
Markdown
# Betrieb auf docker-srv001
|
||
|
||
## Erstinstallation
|
||
|
||
```bash
|
||
mkdir -p /opt/moneyfy && cd /opt/moneyfy
|
||
|
||
# docker-compose.yml und .env.example aus dem Repository holen
|
||
curl -fsSLO https://git.menzel.center/menzeljonas/moneyfy/raw/branch/main/docker-compose.yml
|
||
curl -fsSLO https://git.menzel.center/menzeljonas/moneyfy/raw/branch/main/.env.example
|
||
cp .env.example .env
|
||
```
|
||
|
||
In `.env` mindestens setzen:
|
||
|
||
```bash
|
||
POSTGRES_PASSWORD=$(openssl rand -hex 24)
|
||
SECRET_KEY=$(openssl rand -hex 32)
|
||
MONEYFY_ADMIN_PASSWORD=<Startpasswort>
|
||
PUBLIC_BASE_URL=https://moneyfy.menzel.center
|
||
TAG=latest
|
||
```
|
||
|
||
Das externe Proxy-Netz muss existieren – NPMplus bringt es üblicherweise mit:
|
||
|
||
```bash
|
||
docker network inspect proxy >/dev/null 2>&1 || docker network create proxy
|
||
```
|
||
|
||
An der Registry anmelden und starten:
|
||
|
||
```bash
|
||
docker login git.menzel.center
|
||
docker compose up -d
|
||
docker compose logs -f moneyfy-backend
|
||
```
|
||
|
||
Das Backend wartet auf die Datenbank, spielt die Migrationen ein und legt beim
|
||
allerersten Start den Kategoriebaum an. Danach ist die Oberfläche unter
|
||
`http://127.0.0.1:8087` erreichbar.
|
||
|
||
Beim ersten Anmelden gelten `MONEYFY_ADMIN_USER` und `MONEYFY_ADMIN_PASSWORD`;
|
||
die Anwendung verlangt sofort ein neues Passwort. Danach kann
|
||
`MONEYFY_ADMIN_PASSWORD` aus der `.env` entfernt werden.
|
||
|
||
## NPMplus konfigurieren
|
||
|
||
`moneyfy.menzel.center` als **Proxy Host** anlegen:
|
||
|
||
| Feld | Wert |
|
||
|---|---|
|
||
| Domain Names | `moneyfy.menzel.center` |
|
||
| Scheme | `http` |
|
||
| Forward Hostname / IP | `moneyfy-frontend` |
|
||
| Forward Port | `8080` |
|
||
| Cache Assets | aus – der Container setzt die Cache-Kopfzeilen selbst |
|
||
| Block Common Exploits | an |
|
||
| Websockets Support | aus – die Anwendung braucht keine |
|
||
|
||
Unter *SSL*: Zertifikat über Let's Encrypt anfordern, **Force SSL** und **HTTP/2**
|
||
einschalten, **HSTS** aktivieren.
|
||
|
||
Damit NPMplus den Container über seinen Namen erreicht, müssen beide im Netz
|
||
`proxy` liegen. Das erledigt `docker-compose.yml` bereits; prüfen mit:
|
||
|
||
```bash
|
||
docker network inspect proxy --format '{{range .Containers}}{{.Name}} {{end}}'
|
||
```
|
||
|
||
Unter *Advanced* diese Zusatzkonfiguration eintragen. Sie sorgt dafür, dass die
|
||
Anwendung das richtige Schema sieht und Exporte nicht in einen Timeout laufen:
|
||
|
||
```nginx
|
||
proxy_set_header X-Forwarded-Proto $scheme;
|
||
proxy_set_header X-Forwarded-Host $host;
|
||
client_max_body_size 4m;
|
||
proxy_read_timeout 120s;
|
||
```
|
||
|
||
> Die Anmeldung setzt `Secure`-Cookies. Ohne HTTPS – also ohne Zugriff über
|
||
> NPMplus – kommt keine Sitzung zustande. Für einen Test über
|
||
> `http://127.0.0.1:8087` muss `COOKIE_SECURE=false` gesetzt werden.
|
||
|
||
## Aktualisieren
|
||
|
||
Das Ausrollen passiert bewusst von Hand; die CI baut nur die Images.
|
||
|
||
```bash
|
||
cd /opt/moneyfy
|
||
|
||
# Bei fester Version: TAG in .env auf die neue Version setzen.
|
||
docker compose pull
|
||
docker compose up -d
|
||
docker compose logs -f moneyfy-backend
|
||
```
|
||
|
||
Die Migrationen laufen beim Start des Backends automatisch. Ein Blick in die
|
||
Ausgabe zeigt, welche Revision eingespielt wurde.
|
||
|
||
Zurückrollen: `TAG` auf die vorherige Version setzen und erneut
|
||
`docker compose up -d`. **Achtung:** Migrationen werden dabei nicht rückgängig
|
||
gemacht. Vor einem Update mit Schemaänderung immer erst sichern.
|
||
|
||
## Sicherung
|
||
|
||
Zwei Dinge müssen gesichert werden: die Datenbank und das Volume mit den Logos.
|
||
|
||
### Datenbank
|
||
|
||
```bash
|
||
docker compose exec -T moneyfy-db \
|
||
pg_dump -U moneyfy -d moneyfy --format=custom \
|
||
> /var/backups/moneyfy/db-$(date +%F).dump
|
||
```
|
||
|
||
Wiederherstellen:
|
||
|
||
```bash
|
||
docker compose stop moneyfy-backend
|
||
docker compose exec -T moneyfy-db \
|
||
pg_restore -U moneyfy -d moneyfy --clean --if-exists < /var/backups/moneyfy/db-2026-03-01.dump
|
||
docker compose start moneyfy-backend
|
||
```
|
||
|
||
### Logo-Volume
|
||
|
||
```bash
|
||
docker run --rm \
|
||
-v moneyfy-data:/data:ro \
|
||
-v /var/backups/moneyfy:/backup \
|
||
alpine tar czf /backup/logos-$(date +%F).tar.gz -C /data .
|
||
```
|
||
|
||
Wiederherstellen:
|
||
|
||
```bash
|
||
docker run --rm \
|
||
-v moneyfy-data:/data \
|
||
-v /var/backups/moneyfy:/backup \
|
||
alpine sh -c "rm -rf /data/* && tar xzf /backup/logos-2026-03-01.tar.gz -C /data"
|
||
```
|
||
|
||
Die Logos lassen sich zur Not auch neu beschaffen – die Datenbank nicht.
|
||
|
||
### Tägliche Sicherung per Cron
|
||
|
||
`/opt/moneyfy/backup.sh`:
|
||
|
||
```bash
|
||
#!/bin/sh
|
||
set -eu
|
||
|
||
ZIEL=/var/backups/moneyfy
|
||
TAG=$(date +%F)
|
||
mkdir -p "$ZIEL"
|
||
|
||
cd /opt/moneyfy
|
||
docker compose exec -T moneyfy-db \
|
||
pg_dump -U moneyfy -d moneyfy --format=custom > "$ZIEL/db-$TAG.dump"
|
||
|
||
docker run --rm \
|
||
-v moneyfy-data:/data:ro \
|
||
-v "$ZIEL:/backup" \
|
||
alpine tar czf "/backup/logos-$TAG.tar.gz" -C /data .
|
||
|
||
# Älteres als 30 Tage entfernen.
|
||
find "$ZIEL" -name 'db-*.dump' -mtime +30 -delete
|
||
find "$ZIEL" -name 'logos-*.tar.gz' -mtime +30 -delete
|
||
```
|
||
|
||
```cron
|
||
30 3 * * * /opt/moneyfy/backup.sh >> /var/log/moneyfy-backup.log 2>&1
|
||
```
|
||
|
||
Die Sicherungen anschließend auf ein anderes System spiegeln – eine Kopie auf
|
||
demselben Host hilft bei einem Plattenausfall nicht.
|
||
|
||
## Fehlersuche
|
||
|
||
**Backend startet nicht, Log endet bei „Warte auf die Datenbank“**
|
||
Die Datenbank ist nicht gesund. `docker compose ps` und
|
||
`docker compose logs moneyfy-db` prüfen; meist stimmt `POSTGRES_PASSWORD` in der
|
||
`.env` nicht mit dem im Volume hinterlegten Passwort überein. Ein bereits
|
||
angelegtes Volume übernimmt kein neues Passwort.
|
||
|
||
**`SECRET_KEY ist nicht gesetzt`**
|
||
Die Anwendung verweigert in Produktion den Start mit dem Platzhalterwert.
|
||
`openssl rand -hex 32` erzeugt einen passenden Schlüssel. Wird er später
|
||
geändert, sind alle Sitzungen ungültig – das ist beabsichtigt.
|
||
|
||
**Anmeldung schlägt fehl**
|
||
|
||
Drei Ursachen kommen in Frage, in dieser Reihenfolge prüfen:
|
||
|
||
1. **Der Benutzer wurde mit einem anderen Passwort angelegt.** Die Erstanlage
|
||
greift nur, solange die Benutzertabelle leer ist. Wer `.env.example` zuerst
|
||
unverändert übernimmt und startet, bekommt einen Benutzer mit dem Platzhalter
|
||
– ein späteres Ändern von `MONEYFY_ADMIN_PASSWORD` bleibt dann wirkungslos.
|
||
Abhilfe:
|
||
|
||
```bash
|
||
docker compose exec moneyfy-backend python -m app.scripts.reset_password \
|
||
--username admin --password "neues-passwort"
|
||
```
|
||
|
||
2. **Der Container kennt den neuen Wert noch nicht.** `docker compose restart`
|
||
behält die alte Umgebung. Nach einer Änderung an der `.env` muss der
|
||
Container neu erstellt werden:
|
||
|
||
```bash
|
||
docker compose up -d --force-recreate moneyfy-backend
|
||
docker compose exec moneyfy-backend printenv MONEYFY_ADMIN_PASSWORD
|
||
```
|
||
|
||
3. **Kein HTTPS.** Die Cookies sind `Secure` gesetzt; über eine reine
|
||
HTTP-Verbindung verwirft der Browser sie. Typisches Bild: **der Bildschirm
|
||
flackert kurz und die Anmeldemaske erscheint erneut, ohne Fehlermeldung.**
|
||
Seit 0.1.2 erklärt die Oberfläche das ausdrücklich, und im Log steht:
|
||
|
||
> `Anmeldung über … ohne HTTPS bei COOKIE_SECURE=true – der Browser verwirft
|
||
> das Sitzungs-Cookie …`
|
||
|
||
Abhilfe: über NPMplus mit HTTPS zugreifen, oder für einen Test auf HTTP:
|
||
|
||
```bash
|
||
# in der .env
|
||
COOKIE_SECURE=false
|
||
```
|
||
|
||
```bash
|
||
# restart genügt nicht – nur up -d übernimmt die geänderte Umgebung
|
||
docker compose up -d --force-recreate moneyfy-backend
|
||
```
|
||
|
||
Welcher Fall vorliegt, verrät das Log:
|
||
|
||
```bash
|
||
docker compose logs moneyfy-backend | grep -iE "administrator|MONEYFY_ADMIN"
|
||
```
|
||
|
||
**Firmen bekommen kein Logo**
|
||
Ohne Netzzugang findet nur der lokale Markenkatalog etwas; unbekannte Firmen
|
||
erhalten einen erzeugten Avatar. Das ist so gewollt. Mit
|
||
`docker compose exec moneyfy-backend python -c "from app.services.logos import simple_icon_index; print(simple_icon_index().version)"`
|
||
lässt sich prüfen, ob der Katalog im Image liegt.
|
||
|
||
**Keine Benachrichtigungen**
|
||
`SCHEDULER_ENABLED` und `NOTIFICATIONS_ENABLED` prüfen, dann in der Oberfläche
|
||
unter *Einstellungen → Benachrichtigungen* den Einrichtungsstand ansehen und
|
||
eine Testnachricht schicken. Das Versandprotokoll steht auf derselben Seite.
|
||
|
||
**Speicherplatz**
|
||
```bash
|
||
docker system df
|
||
docker compose exec moneyfy-db psql -U moneyfy -d moneyfy -c "\l+"
|
||
docker run --rm -v moneyfy-data:/data:ro alpine du -sh /data
|
||
```
|