304 lines
13 KiB
Markdown
304 lines
13 KiB
Markdown
# DEPLOYMENT_ADMIN.md – Login-Editor für larpaso.de
|
||
|
||
Ergänzt DEPLOYMENT.md um einen eigenen, öffentlich erreichbaren, aber login-geschützten
|
||
Editor unter **`https://admin.larpaso.de`**. Dort können Texte, Bilder, Links, Impressum,
|
||
Datenschutz sowie Schriftarten/-größen und alle Farben der Seite geändert werden.
|
||
„Speichern & veröffentlichen" baut die Seite neu und die Änderung ist sofort auf
|
||
`larpaso.de` sichtbar – ohne weiteren Server-Zugriff nötig.
|
||
|
||
Wie in DEPLOYMENT.md: **Teil A** ist bereits im Repo erledigt (Claude Code) und lokal
|
||
getestet. **Teil B** unten führst du selbst per SSH auf dem Server aus – das ist eine
|
||
vollständige Schritt-für-Schritt-Anleitung zum Copy-Pasten. Claude Code hat zu keinem
|
||
Zeitpunkt Zugriff auf Benutzername/Passwort/Secrets oder den Server selbst.
|
||
|
||
---
|
||
|
||
## Was der Editor kann
|
||
|
||
- **Texte**: alle Überschriften, Absätze, Listen, FAQ, Preis-Punkte, Mappe-Einträge usw.
|
||
der Startseite – inklusive Impressum und Datenschutzerklärung. Längere Texte haben einen
|
||
Rich-Text-Editor mit Knöpfen für Fett/Kursiv/Unterstrichen sowie eine Schriftart-Auswahl,
|
||
mit der einzelne markierte Wörter/Sätze eine eigene Schriftart bekommen können (aus der
|
||
gleichen kuratierten Liste wie im Design-Tab) – unabhängig von den zwei Grundschriften.
|
||
- **Bilder**: Logo, Mappe-Screenshots, Team-Foto, plus optional eigene Bilder anstelle der
|
||
eingebauten Google-Vorschau und des PDF/Tabellen-Vergleichs.
|
||
- **Links**: Menüpunkte, E-Mail-Adresse, Kontakt-Angaben.
|
||
- **Design**: Schriftart für Überschriften/Fließtext (Auswahl aus gängigen Google Fonts
|
||
oder Systemschrift), Schriftgrößen (7 Stufen, per Schieberegler), und *alle* Farben der
|
||
Seite einzeln über Hex-Feld, RGB-Schieberegler und Transparenz-Regler.
|
||
- **Übersicht**: die Oberfläche ist in Reiter/Tabs gegliedert (linke Seitenleiste, gruppiert
|
||
in „Inhalte" und „Design") statt einer langen durchgehenden Seite.
|
||
|
||
---
|
||
|
||
## Was sich technisch ändert
|
||
|
||
- Neuer Dienst `admin` (Node/Express, `admin/`) mit Login, Bearbeitungsoberfläche und
|
||
einem „Veröffentlichen"-Knopf, der intern `npm run build` ausführt.
|
||
- Der bestehende `website`-Dienst (nginx) serviert nicht mehr aus dem Image gebackene
|
||
Dateien, sondern aus einem **gemeinsamen Volume** (`site-dist`), das der `admin`-Dienst
|
||
nach jedem „Veröffentlichen" neu befüllt. Kein Neustart von `website` nötig.
|
||
- Bearbeitete Inhalte (`content/site.json`, `content/theme.json`) und hochgeladene Bilder
|
||
(`public/uploads/`) liegen auf eigenen Volumes, damit sie ein Image-Update überleben.
|
||
- Login: ein oder mehrere feste Benutzername/Passwort-Paare (bcrypt-Hash), Session-Cookie
|
||
(12h, httpOnly, Secure, SameSite=Strict), Rate-Limit (5 Fehlversuche → 15 Min. Sperre pro IP).
|
||
|
||
---
|
||
|
||
## TEIL A – im Repo (bereits erledigt)
|
||
|
||
- `admin/` – Editor-Backend + -Oberfläche (Login, Formulare, Bild-Upload, Farb-/Font-/
|
||
Größen-Editor, Build-Trigger).
|
||
- `content/site.json`, `content/theme.json` – alle editierbaren Inhalte bzw. Design-Werte.
|
||
- `Dockerfile.admin` – Image für den `admin`-Dienst.
|
||
- `Dockerfile` (angepasst) – `website` seedet ein leeres `site-dist`-Volume beim ersten
|
||
Start aus dem gebackenen Build, statt Dateien fest einzubacken.
|
||
- `docker-entrypoint-seed.sh`, `docker-entrypoint-admin-seed.sh` – Seed-Skripte für die
|
||
Volumes.
|
||
- Lokal geprüft: `npm run build` läuft fehlerfrei; Login, Rate-Limit-Sperre, Speichern
|
||
(Texte, Bilder, Impressum/Datenschutz, Farben, Schriftarten, Schriftgrößen),
|
||
Bild-Upload und Veröffentlichen wurden lokal gegen den Admin-Server End-to-End getestet.
|
||
|
||
---
|
||
|
||
## TEIL B – Schritt für Schritt per SSH (machst du)
|
||
|
||
Alles unten in dieser Reihenfolge ausführen. Wo `<...>` steht, durch echte Werte ersetzen.
|
||
|
||
### B0. Voraussetzung: Code muss auf dem Server ankommen können
|
||
Damit `git pull` in B1 etwas findet, muss dieser Stand vorher nach
|
||
`git.larpaso.de/pascal/larpaso-website` gepusht sein. Frag im Chat nach, ob das schon
|
||
passiert ist, falls du direkt startest.
|
||
|
||
### B1. Repo aktualisieren
|
||
```bash
|
||
ssh deploy@<server>
|
||
cd ~/sites/larpaso-website
|
||
git pull
|
||
```
|
||
|
||
### B2. Platzhalter für `~/stack/admin.env` anlegen (NICHT ins Git-Repo!)
|
||
Erstmal nur eine leere Datei, damit Docker Compose in B3/B5 nicht meckert, dass sie fehlt.
|
||
Die echten Werte kommen in B6 rein.
|
||
```bash
|
||
touch ~/stack/admin.env
|
||
chmod 600 ~/stack/admin.env
|
||
```
|
||
|
||
### B3. Dienste in `~/stack/docker-compose.yml` ergänzen
|
||
```bash
|
||
nano ~/stack/docker-compose.yml
|
||
```
|
||
Beim bestehenden `website`-Dienst ein `volumes:` ergänzen:
|
||
```yaml
|
||
website:
|
||
build:
|
||
context: /home/deploy/sites/larpaso-website
|
||
restart: unless-stopped
|
||
networks: [web]
|
||
volumes:
|
||
- site-dist:/usr/share/nginx/html
|
||
```
|
||
|
||
Neuen `admin`-Dienst unter `services:` ergänzen:
|
||
```yaml
|
||
admin:
|
||
build:
|
||
context: /home/deploy/sites/larpaso-website
|
||
dockerfile: Dockerfile.admin
|
||
restart: unless-stopped
|
||
networks: [web]
|
||
env_file:
|
||
- /home/deploy/stack/admin.env
|
||
volumes:
|
||
- site-dist:/site-dist
|
||
- admin-content:/app/content
|
||
- admin-uploads:/app/public/uploads
|
||
```
|
||
(Kein `ports:` bei beiden Diensten – Caddy erreicht sie intern über den Container-Namen.)
|
||
|
||
Im bestehenden **obersten** `volumes:`-Block der Datei ergänzen (nicht neu anlegen):
|
||
```yaml
|
||
volumes:
|
||
site-dist:
|
||
admin-content:
|
||
admin-uploads:
|
||
```
|
||
|
||
### B4. Caddy-Block ergänzen
|
||
```bash
|
||
nano ~/stack/caddy/Caddyfile
|
||
```
|
||
Hinzufügen:
|
||
```caddyfile
|
||
admin.larpaso.de {
|
||
reverse_proxy admin:4321
|
||
}
|
||
```
|
||
|
||
### B5. Admin-Image bauen
|
||
```bash
|
||
cd ~/stack
|
||
docker compose build admin
|
||
```
|
||
Das baut das Image für den Login-Editor – inklusive eines sauberen `npm ci` für die
|
||
Admin-Abhängigkeiten (bcryptjs, Express usw.), im selben zuverlässigen Schritt, der auch
|
||
gleich für den Live-Betrieb verwendet wird.
|
||
|
||
### B6. Login-Zugangsdaten erzeugen
|
||
Jetzt mit dem gerade gebauten Image statt einem Wegwerf-Container – robuster als ein
|
||
Ad-hoc-`npm install` (das kann mit dem bekannten npm-Fehler „Tracker 'idealTree' already
|
||
exists" fehlschlagen):
|
||
```bash
|
||
docker compose run --rm admin node admin/hash-password.js "dein-neues-passwort" | sed 's/\$/$$/g'
|
||
```
|
||
Gibt einen bcrypt-Hash aus, bei dem jedes `$` bereits verdoppelt ist (`$$2a$$12$$...`) –
|
||
**genau so, mit den doppelten `$`, in B7 einfügen.** Docker Compose interpretiert einzelne
|
||
`$` in `env_file`-Werten nämlich selbst als Variablen (siehe Warnung weiter unten, falls
|
||
das schiefgeht) – `$$` ist Compose' eigene Escape-Regel dafür, kein Tippfehler.
|
||
|
||
Zufälliges Session-Secret erzeugen (rein hexadezimal, kein `$` enthalten, keine
|
||
Verdopplung nötig):
|
||
```bash
|
||
docker compose run --rm admin node -e "console.log(require('crypto').randomBytes(32).toString('hex'))"
|
||
```
|
||
Auch kopieren.
|
||
|
||
**Optional – zweiten Benutzer anlegen** (z. B. für Lara): denselben Hash-Befehl nochmal
|
||
mit ihrem Passwort ausführen und den (verdoppelten) Hash ebenfalls kopieren. Ein
|
||
Session-Secret reicht für alle Benutzer, das muss nicht nochmal erzeugt werden.
|
||
```bash
|
||
docker compose run --rm admin node admin/hash-password.js "ihr-neues-passwort" | sed 's/\$/$$/g'
|
||
```
|
||
|
||
### B7. `~/stack/admin.env` mit echten Werten befüllen
|
||
Am einfachsten mit `nano` (kein Heredoc nötig):
|
||
```bash
|
||
nano ~/stack/admin.env
|
||
```
|
||
Inhalt (Beispiel – deine Werte aus B6 einsetzen, die Hashes **mit den doppelten `$`**
|
||
genau so wie von `sed` ausgegeben, nicht die ursprüngliche, unverdoppelte Variante):
|
||
```
|
||
NODE_ENV=production
|
||
ADMIN_USERNAME=pascal
|
||
ADMIN_PASSWORD_HASH=$$2a$$12$$dein.eigentlicher.hash.hier
|
||
SESSION_SECRET=dein-hex-string-hier
|
||
```
|
||
**Nur falls du einen zweiten Benutzer angelegt hast**, zwei weitere Zeilen ergänzen
|
||
(Muster lässt sich mit `_3`, `_4`, ... beliebig fortsetzen):
|
||
```
|
||
ADMIN_USERNAME_2=lara
|
||
ADMIN_PASSWORD_HASH_2=$$2a$$12$$laras.hash.hier
|
||
```
|
||
Speichern: `Strg+O`, `Enter`, `Strg+X`. Danach:
|
||
```bash
|
||
chmod 600 ~/stack/admin.env
|
||
```
|
||
**Kontrolle** (jeder Hash muss inklusive der verdoppelten `$` **63 Zeichen** lang sein –
|
||
60 für den eigentlichen bcrypt-Hash + 3 zusätzliche `$`):
|
||
```bash
|
||
grep HASH ~/stack/admin.env | awk -F= '{print $1": "length($2)" Zeichen"}'
|
||
```
|
||
|
||
### B8. DNS bei IONOS
|
||
- Neuer A-Eintrag: Hostname `admin` → Server-IPv4 (gleiche IP wie `@`).
|
||
- Kurz warten/prüfen: `nslookup admin.larpaso.de` muss die Server-IP liefern, bevor B9
|
||
läuft (sonst bekommt Caddy kein Zertifikat).
|
||
|
||
### B9. Bauen & starten
|
||
```bash
|
||
cd ~/stack
|
||
docker compose build website
|
||
docker compose up -d website admin
|
||
docker compose restart caddy
|
||
docker compose logs -f caddy # auf "certificate obtained successfully" für admin.larpaso.de warten, dann Strg+C
|
||
```
|
||
(`admin` wurde schon in B5 gebaut – falls du seitdem nochmal `git pull` gemacht hast,
|
||
einmal `docker compose build admin` vorweg wiederholen.)
|
||
|
||
### B10. Prüfen
|
||
1. `https://admin.larpaso.de/admin/login` öffnen, mit den Zugangsdaten aus B6/B7 anmelden.
|
||
2. Eine Kleinigkeit ändern (z. B. Telefonnummer im Abschnitt „Kontakt" oder eine Farbe im
|
||
Abschnitt „Design – Farben"), **Speichern & veröffentlichen** klicken.
|
||
3. Build-Ausgabe sollte mit „Complete!" enden.
|
||
4. `https://larpaso.de` neu laden (ggf. Hard-Reload / Cache leeren) – Änderung sollte
|
||
sofort da sein.
|
||
|
||
Fertig. Ab jetzt kannst du alle Texte, Bilder, Links und das Design selbst über
|
||
`admin.larpaso.de` pflegen, ohne mich oder SSH zu brauchen.
|
||
|
||
---
|
||
|
||
## Künftige Updates am Code (Admin-Backend selbst)
|
||
|
||
Ändert sich `admin/` oder das Editor-Frontend am Code (nicht über die Editor-Oberfläche,
|
||
sondern durch mich im Chat), reicht danach:
|
||
```bash
|
||
cd ~/sites/larpaso-website && git pull
|
||
cd ~/stack && docker compose build admin && docker compose up -d admin
|
||
```
|
||
`content/site.json`, `content/theme.json` und hochgeladene Bilder bleiben unangetastet
|
||
(liegen auf eigenen Volumes, nicht im Image).
|
||
|
||
## Content-Updates über Git/Claude Code, ohne den Editor zu überschreiben
|
||
|
||
Seit es den Editor gibt, liegt der **echte Live-Inhalt** (`content/site.json`,
|
||
`content/theme.json`) auf eigenen Volumes auf dem Server, nicht mehr im
|
||
Git-Image – ein einfaches `git pull` + `docker compose build website`
|
||
ändert an den Live-Inhalten deshalb **nichts** mehr (das Seed-Skript befüllt
|
||
die Volumes nur einmalig, wenn sie leer sind).
|
||
|
||
Damit Claude Code trotzdem Content-Änderungen pushen kann, ohne Änderungen
|
||
zu überschreiben, die zwischenzeitlich über den Editor gemacht wurden, gibt
|
||
es zwei Skripte im Repo (auf dem Server, aus `~/stack` ausführen):
|
||
|
||
1. **Vor** einer Content-Änderung durch Claude Code: aktuellen Live-Stand
|
||
nach Git holen (nur nötig, falls seit dem letzten Mal über den Editor was
|
||
geändert wurde – bei keiner Änderung passiert nichts):
|
||
```bash
|
||
cd ~/stack
|
||
~/sites/larpaso-website/sync-content-from-live.sh
|
||
```
|
||
2. Im Chat mit Claude Code die gewünschte Änderung beschreiben – Claude
|
||
Code ändert `content/site.json`/`theme.json` lokal auf Basis des gerade
|
||
synchronisierten Stands, testet den Build und pusht nach `main`.
|
||
3. **Nach** dem Push: Git-Stand auf den Server holen und live veröffentlichen
|
||
(baut über denselben Weg wie „Speichern & veröffentlichen" im Editor,
|
||
ohne den `website`- oder `admin`-Dienst neu zu bauen):
|
||
```bash
|
||
cd ~/sites/larpaso-website && git pull
|
||
cd ~/stack
|
||
./sync-content-from-live.sh # kann man sich sparen, falls Schritt 1 schon frisch war
|
||
~/sites/larpaso-website/publish-content-to-live.sh
|
||
```
|
||
|
||
**Wichtig:** Das gilt nur für `content/site.json`/`theme.json` (Texte,
|
||
Bilder-Referenzen, Design-Werte). Änderungen am Code selbst (`admin/`,
|
||
`src/`) laufen weiterhin über den normalen Weg (`docker compose build
|
||
website`/`admin` + `up -d`, siehe oben).
|
||
|
||
**Ändert sich in einem Push beides gleichzeitig** (Content **und** Code,
|
||
z. B. neue Felder in `content/site.json` plus die passende Template-Änderung
|
||
in `src/`) – **unbedingt in dieser Reihenfolge**, sonst baut
|
||
`publish-content-to-live.sh` mit dem alten Template und die Content-Änderung
|
||
scheint wirkungslos:
|
||
```bash
|
||
cd ~/sites/larpaso-website && git pull
|
||
cd ~/stack
|
||
docker compose build admin && docker compose up -d admin # zuerst: neuer Code im Container
|
||
~/sites/larpaso-website/publish-content-to-live.sh # danach erst: baut/veröffentlicht mit dem neuen Code
|
||
```
|
||
|
||
## Bekannte Grenzen
|
||
|
||
- Mehrere feste Logins möglich (`ADMIN_USERNAME`/`ADMIN_PASSWORD_HASH`, `_2`, `_3`, ...),
|
||
aber kein echtes Mehrbenutzer-System – alle Logins haben dieselben Rechte, es gibt keine
|
||
Rollen und keine Passwort-Reset-Funktion in der Oberfläche. Neues/geändertes Passwort:
|
||
`docker compose run --rm admin node admin/hash-password.js "..."` ausführen (wie B6),
|
||
Hash in `admin.env` eintragen, dann `docker compose up -d admin`.
|
||
- Sessions sind In-Memory: Ein Neustart des `admin`-Containers meldet alle ab.
|
||
- Es gibt keine Versionshistorie der Inhalte oder des Designs – beides liegt aber auf dem
|
||
Server und kann bei Bedarf manuell gesichert werden (z. B. regelmäßiges Backup der
|
||
Volumes `admin-content` und `admin-uploads` einplanen, wie für die anderen Volumes auch).
|
||
- Schriftarten sind auf eine kuratierte Liste gängiger Google Fonts + Systemschrift
|
||
begrenzt (keine eigenen Font-Dateien hochladbar) – bei Bedarf im Chat erweiterbar.
|