Schritt-für-Schritt-Deployment-Anleitung für neuen Server
Neues DEPLOYMENT.md: Voraussetzungen, Repository holen, .env.local konfigurieren, docker compose up --build, Admin-Zugangsdaten aus ZUGANGSDATEN.md abholen, Reverse-Proxy/HTTPS (Caddy-Beispiel), Updates, Backup der Docker-Volumes. Aus README.md verlinkt. .env.example: LOCAL_PG_PASSWORD war bisher nirgends dokumentiert, obwohl docker-compose.yml die DATABASE_URL des App-Containers daraus zusammenbaut (die dortige DATABASE_URL-Zeile wird beim Docker-Compose-Betrieb ignoriert) – beim Schreiben der Anleitung aufgefallen und ergänzt. README.md: RSS-Feed und Vorschläge-Badge in der Funktionstabelle ergänzt.
This commit is contained in:
+10
-1
@@ -1,7 +1,16 @@
|
|||||||
# Vorlage für .env.local (Entwicklung) bzw. die Umgebungsvariablen
|
# Vorlage für .env.local (Entwicklung) bzw. die Umgebungsvariablen
|
||||||
# beim Hoster (Live-Betrieb). Echte Werte niemals committen!
|
# beim Hoster (Live-Betrieb). Echte Werte niemals committen!
|
||||||
|
|
||||||
# Verbindung zur (selbst gehosteten) PostgreSQL-Datenbank.
|
# Nur für Docker Compose relevant: Passwort für den mitgelieferten
|
||||||
|
# PostgreSQL-Container (Dienst "db" in docker-compose.yml). Daraus baut
|
||||||
|
# docker-compose.yml die DATABASE_URL für die App-Container selbst
|
||||||
|
# zusammen – die Zeile unten wird beim Betrieb per Docker Compose
|
||||||
|
# NICHT verwendet, nur bei manuellem "npm run dev"/"npm run start"
|
||||||
|
# gegen eine selbst betriebene PostgreSQL-Instanz.
|
||||||
|
LOCAL_PG_PASSWORD=<beliebiges-sicheres-passwort>
|
||||||
|
|
||||||
|
# Verbindung zur PostgreSQL-Datenbank (nur für den Betrieb OHNE Docker
|
||||||
|
# Compose relevant, s. o.).
|
||||||
DATABASE_URL=postgres://postgres:<passwort>@localhost:5432/canteen_menu
|
DATABASE_URL=postgres://postgres:<passwort>@localhost:5432/canteen_menu
|
||||||
|
|
||||||
# Öffentliche URL, unter der die App erreichbar ist (Schema + Domain).
|
# Öffentliche URL, unter der die App erreichbar ist (Schema + Domain).
|
||||||
|
|||||||
+165
@@ -0,0 +1,165 @@
|
|||||||
|
# Deployment auf einem neuen Server
|
||||||
|
|
||||||
|
Schritt-für-Schritt-Anleitung, um Canteen Menu auf einem frischen
|
||||||
|
(Linux-)Server produktiv zu betreiben. Die App läuft vollständig selbst
|
||||||
|
gehostet (PostgreSQL + eigene Auth), einzige optionale externe
|
||||||
|
Abhängigkeit ist DeepL für automatische Übersetzungen.
|
||||||
|
|
||||||
|
## Voraussetzungen
|
||||||
|
|
||||||
|
- Ein Server (VM oder Root-Server) mit Docker und Docker Compose v2
|
||||||
|
(`docker compose version` sollte funktionieren; auf den meisten
|
||||||
|
aktuellen Distributionen per `apt install docker.io
|
||||||
|
docker-compose-v2` bzw. dem [offiziellen Docker-Install-Skript](https://docs.docker.com/engine/install/)
|
||||||
|
installierbar).
|
||||||
|
- Eine Domain, deren DNS-A/AAAA-Eintrag auf die Server-IP zeigt (z. B.
|
||||||
|
`menu.example.de`). Ohne eigene Domain funktioniert die App auch
|
||||||
|
unter der reinen Server-IP, dann aber ohne gültiges HTTPS-Zertifikat
|
||||||
|
und ohne funktionierende Passkeys (siehe unten).
|
||||||
|
- Mindestens 1 GB RAM frei (App + PostgreSQL sind genügsam, für ~250
|
||||||
|
Mitarbeiter reicht die kleinste übliche VM-Größe).
|
||||||
|
|
||||||
|
## 1. Repository auf den Server holen
|
||||||
|
|
||||||
|
```bash
|
||||||
|
git clone https://github.com/<dein-fork-oder-repo>/canteen-menu.git
|
||||||
|
cd canteen-menu
|
||||||
|
```
|
||||||
|
|
||||||
|
(Oder per `git pull`/`scp`, falls kein direkter Git-Zugriff vom Server
|
||||||
|
aus gewünscht ist.)
|
||||||
|
|
||||||
|
## 2. Konfiguration anlegen
|
||||||
|
|
||||||
|
```bash
|
||||||
|
cp .env.example .env.local
|
||||||
|
```
|
||||||
|
|
||||||
|
`.env.local` mit einem Editor öffnen und ausfüllen:
|
||||||
|
|
||||||
|
| Variable | Was rein muss |
|
||||||
|
| --- | --- |
|
||||||
|
| `LOCAL_PG_PASSWORD` | Ein neues, zufälliges Passwort (z. B. `openssl rand -base64 24`) – wird beim ersten Start zum Datenbank-Passwort des mitgelieferten PostgreSQL-Containers |
|
||||||
|
| `APP_URL` | Die öffentliche URL mit Schema, z. B. `https://menu.example.de` (auch wenn HTTPS erst in Schritt 5 eingerichtet wird – schon jetzt korrekt eintragen, da daraus u. a. die Passkey-Domain abgeleitet wird) |
|
||||||
|
| `SITE_TITLE` | Optional, Titel im Browser-Tab/Überschrift ohne Logo |
|
||||||
|
| `ADMIN_EMAIL` | Optional, E-Mail des automatisch angelegten Admin-Erstnutzers. Ohne Angabe: `admin@<Hostname aus APP_URL>` |
|
||||||
|
| `DEEPL_API_KEY` | Optional, nur für automatische Übersetzung |
|
||||||
|
|
||||||
|
`DATABASE_URL` in `.env.local` **nicht** anpassen – die wird nur für
|
||||||
|
den Betrieb ohne Docker gebraucht (siehe README) und beim
|
||||||
|
Docker-Compose-Start ignoriert.
|
||||||
|
|
||||||
|
Zusätzlich eine leere Datei für die automatisch generierten
|
||||||
|
Admin-Zugangsdaten anlegen, da sie per Bind-Mount in den Container
|
||||||
|
eingebunden wird:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
touch ZUGANGSDATEN.md
|
||||||
|
```
|
||||||
|
|
||||||
|
## 3. App starten
|
||||||
|
|
||||||
|
```bash
|
||||||
|
docker compose --env-file .env.local up -d --build
|
||||||
|
```
|
||||||
|
|
||||||
|
Das baut das Docker-Image, startet PostgreSQL und die App, wendet beim
|
||||||
|
ersten Start automatisch das Datenbankschema an und legt – da die
|
||||||
|
Datenbank leer ist – einen einzigen Admin-Benutzer mit zufällig
|
||||||
|
generiertem Passwort an.
|
||||||
|
|
||||||
|
Kurz prüfen, ob beides läuft:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
docker compose ps
|
||||||
|
docker compose logs app --tail 30
|
||||||
|
```
|
||||||
|
|
||||||
|
In den Logs sollte u. a. `bootstrap-admin – Admin angelegt: ...`
|
||||||
|
stehen.
|
||||||
|
|
||||||
|
## 4. Admin-Zugangsdaten abholen
|
||||||
|
|
||||||
|
```bash
|
||||||
|
cat ZUGANGSDATEN.md
|
||||||
|
```
|
||||||
|
|
||||||
|
Enthält E-Mail-Adresse und Passwort des automatisch angelegten
|
||||||
|
Admin-Kontos. Direkt nach dem ersten Login unter „Mein Konto“ das
|
||||||
|
Passwort ändern und optional einen Passkey registrieren.
|
||||||
|
|
||||||
|
Die App ist jetzt unter `http://<server-ip>:3000` erreichbar – für den
|
||||||
|
produktiven Betrieb fehlt noch HTTPS/die Domain (nächster Schritt).
|
||||||
|
|
||||||
|
## 5. Reverse-Proxy + HTTPS einrichten
|
||||||
|
|
||||||
|
Die App selbst spricht nur HTTP auf Port 3000; TLS/HTTPS übernimmt ein
|
||||||
|
Reverse-Proxy davor. Am einfachsten mit [Caddy](https://caddyserver.com/)
|
||||||
|
(automatisches Let’s-Encrypt-Zertifikat, keine manuelle Zertifikats-
|
||||||
|
verwaltung nötig):
|
||||||
|
|
||||||
|
```bash
|
||||||
|
sudo apt install caddy # oder: siehe caddyserver.com/docs/install
|
||||||
|
```
|
||||||
|
|
||||||
|
`/etc/caddy/Caddyfile`:
|
||||||
|
|
||||||
|
```
|
||||||
|
menu.example.de {
|
||||||
|
reverse_proxy localhost:3000
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
```bash
|
||||||
|
sudo systemctl reload caddy
|
||||||
|
```
|
||||||
|
|
||||||
|
Caddy holt beim ersten Aufruf automatisch ein Zertifikat und leitet
|
||||||
|
danach HTTP→HTTPS um. Alternative: nginx + certbot, falls bereits ein
|
||||||
|
nginx-Setup existiert (Standard-`proxy_pass`-Konfiguration auf
|
||||||
|
`http://127.0.0.1:3000`, Zertifikat separat per `certbot --nginx`).
|
||||||
|
|
||||||
|
Danach in `.env.local` sicherstellen, dass `APP_URL=https://menu.example.de`
|
||||||
|
gesetzt ist (Schema `https`, keine Portangabe), und die App neu
|
||||||
|
starten, falls diese Variable nach Schritt 2 noch geändert wurde:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
docker compose --env-file .env.local up -d
|
||||||
|
```
|
||||||
|
|
||||||
|
## 6. Danach
|
||||||
|
|
||||||
|
- Passkeys funktionieren erst mit korrekt gesetzter `APP_URL` (RP-Domain
|
||||||
|
wird direkt daraus abgeleitet) und über HTTPS (Passkeys verlangen eine
|
||||||
|
sichere Origin, `localhost` ausgenommen).
|
||||||
|
- Weitere Kantinenmitarbeiter/Admins unter „Benutzer“ (nur als Admin
|
||||||
|
sichtbar) anlegen.
|
||||||
|
- Essenszeiten, Gerichte, Allergene/Zusatzstoffe sind zu Beginn leer und
|
||||||
|
werden im Kantinen-Bereich gepflegt.
|
||||||
|
- Logo/Favicon/Farben unter „Design“ (nur Admin) anpassen.
|
||||||
|
|
||||||
|
## Updates einspielen
|
||||||
|
|
||||||
|
```bash
|
||||||
|
git pull
|
||||||
|
docker compose --env-file .env.local up -d --build
|
||||||
|
```
|
||||||
|
|
||||||
|
Neue Datenbank-Migrationen (`db/migrations/*.sql`) werden beim Start
|
||||||
|
automatisch und idempotent angewendet, bestehende Daten bleiben
|
||||||
|
erhalten.
|
||||||
|
|
||||||
|
## Backup
|
||||||
|
|
||||||
|
Zwei Docker-Volumes enthalten alle persistenten Daten:
|
||||||
|
|
||||||
|
- `canteen-menu_pgdata` – die komplette PostgreSQL-Datenbank
|
||||||
|
- `canteen-menu_branding_data` – hochgeladenes Logo/Favicon
|
||||||
|
|
||||||
|
```bash
|
||||||
|
docker run --rm -v canteen-menu_pgdata:/data -v "$PWD":/backup alpine \
|
||||||
|
tar czf /backup/pgdata-backup.tar.gz -C /data .
|
||||||
|
```
|
||||||
|
|
||||||
|
Für ein reines Datenbank-Backup eignet sich auch `docker compose exec db
|
||||||
|
pg_dump -U postgres canteen_menu > backup.sql`.
|
||||||
@@ -11,14 +11,16 @@ DeepL als einzige externe API (optional). Läuft vollständig selbst
|
|||||||
gehostet, keine Cloud-Abhängigkeit außer optional DeepL.
|
gehostet, keine Cloud-Abhängigkeit außer optional DeepL.
|
||||||
|
|
||||||
Änderungen je Version stehen in [CHANGELOG.md](CHANGELOG.md), Git-Tags
|
Änderungen je Version stehen in [CHANGELOG.md](CHANGELOG.md), Git-Tags
|
||||||
markieren die jeweiligen Versionsstände (`git tag`).
|
markieren die jeweiligen Versionsstände (`git tag`). Schritt-für-Schritt-
|
||||||
|
Anleitung für die Inbetriebnahme auf einem neuen Server:
|
||||||
|
[DEPLOYMENT.md](DEPLOYMENT.md).
|
||||||
|
|
||||||
## Funktionen
|
## Funktionen
|
||||||
|
|
||||||
| Bereich | Funktionen |
|
| Bereich | Funktionen |
|
||||||
| --- | --- |
|
| --- | --- |
|
||||||
| Öffentlich (ohne Login) | Wochenplan Mo–Fr mit frei konfigurierbaren Essenszeiten; Navigation vorherige/nächste Woche/Heute; auf schmalen Bildschirmen umschaltbare Tages-/Wochenansicht (Tag ist Standard); Logo zentriert über der Karte; Allergen-/Zusatzstoff-Kürzel je Gericht, Legende unterhalb der Karte; Sprachumschalter Deutsch/Englisch/Polnisch; Rezeptvorschläge einreichen |
|
| Öffentlich (ohne Login) | Wochenplan Mo–Fr mit frei konfigurierbaren Essenszeiten; Navigation vorherige/nächste Woche/Heute; auf schmalen Bildschirmen umschaltbare Tages-/Wochenansicht (Tag ist Standard); Logo zentriert über der Karte; Allergen-/Zusatzstoff-Kürzel je Gericht, Legende unterhalb der Karte; Sprachumschalter Deutsch/Englisch/Polnisch; Rezeptvorschläge einreichen; RSS-Feed (`/feed.xml`, Icon im Kopfbereich) mit einem Eintrag pro Tag zum Abonnieren |
|
||||||
| Kantinen-Team (`/intern`) | Essenszeiten anlegen/bearbeiten/löschen/neu anordnen; Gerichte anlegen/bearbeiten/löschen (inkl. Live-Suche, Mehrfachauswahl zum Batch-Löschen, englischem/polnischem Namen mit automatischer DeepL-Übersetzung) mit Allergenen/Zusatzstoffen je Gericht; Gerichte Tagen/Essenszeiten zuweisen (mehrere pro Zelle) und wieder entfernen; globale Allergen-/Zusatzstofflisten pflegen (ebenfalls mehrsprachig); eingereichte Rezeptvorschläge sichten, übernehmen oder ablehnen; eigenes Konto verwalten (Name, E-Mail, Passwort, Passkeys, Passwort-Anmeldung an/aus) |
|
| Kantinen-Team (`/intern`) | Essenszeiten anlegen/bearbeiten/löschen/neu anordnen; Gerichte anlegen/bearbeiten/löschen (inkl. Live-Suche, Mehrfachauswahl zum Batch-Löschen, englischem/polnischem Namen mit automatischer DeepL-Übersetzung) mit Allergenen/Zusatzstoffen je Gericht; Gerichte per Suche Tagen/Essenszeiten zuweisen (mehrere pro Zelle) und wieder entfernen; globale Allergen-/Zusatzstofflisten pflegen (ebenfalls mehrsprachig); eingereichte Rezeptvorschläge sichten, übernehmen oder ablehnen (Anzahl offener Vorschläge als Badge in der Navigation); eigenes Konto verwalten (Name, E-Mail, Passwort, Passkeys, Passwort-Anmeldung an/aus) |
|
||||||
| Admin (`/admin`) | Kantinenmitarbeiter anlegen/bearbeiten/löschen (inkl. Passwort-Reset mit Wiederholung und Rollenvergabe); Farbgebung der Speisekarte anpassen; Logo und Favicon hochladen/entfernen |
|
| Admin (`/admin`) | Kantinenmitarbeiter anlegen/bearbeiten/löschen (inkl. Passwort-Reset mit Wiederholung und Rollenvergabe); Farbgebung der Speisekarte anpassen; Logo und Favicon hochladen/entfernen |
|
||||||
|
|
||||||
Anmeldung mit E-Mail + Passwort oder alternativ per **Passkey**
|
Anmeldung mit E-Mail + Passwort oder alternativ per **Passkey**
|
||||||
@@ -37,6 +39,7 @@ mit optionaler automatischer Übersetzung über DeepL (siehe
|
|||||||
```
|
```
|
||||||
app/ Next.js-Routen
|
app/ Next.js-Routen
|
||||||
page.tsx Öffentliche Speisekarte
|
page.tsx Öffentliche Speisekarte
|
||||||
|
feed.xml/ RSS-Feed des Speiseplans (öffentlich)
|
||||||
login/ Login (Passwort + Passkey)
|
login/ Login (Passwort + Passkey)
|
||||||
vorschlag/ Öffentliches Rezeptvorschlag-Formular
|
vorschlag/ Öffentliches Rezeptvorschlag-Formular
|
||||||
intern/ Kantinen-Bereich (Rolle: staff oder admin)
|
intern/ Kantinen-Bereich (Rolle: staff oder admin)
|
||||||
|
|||||||
Reference in New Issue
Block a user