- Package: de.krisenvorrat.* -> de.bollwerk.* - Klassen: KrisenvorratApp/Database/Theme -> Bollwerk* - ApplicationId: de.bollwerk.app - Server: BOLLWERK_* Env-Vars, bollwerk HOCON-Config - Docker: bollwerk-server/db/backup Container-Namen - Room DB: bollwerk.db, SharedPrefs: bollwerk_secure_prefs - Export-Dateien: bollwerk_export/inventar - UI-Strings, HTML, Admin-UI: alle auf Bollwerk - Docs, Skills, README angepasst - Alle Tests gruen, Build erfolgreich
218 lines
7.6 KiB
Markdown
218 lines
7.6 KiB
Markdown
---
|
||
name: vps-deploy
|
||
description: "Server auf den VPS (1984 Hosting, Island) deployen, Docker-Container verwalten, Logs prüfen, SSH-Verbindung, Troubleshooting. Trigger-Phrasen: 'deploy', 'deployen', 'VPS', 'Server deployen', 'Server starten', 'Server stoppen', 'Server logs', 'Container', 'Docker VPS', 'production', 'Produktion', '1984', 'Island-Server'."
|
||
---
|
||
|
||
# Skill: VPS Deploy
|
||
|
||
Deployt den Bollwerk Ktor-Server auf den 1984 Hosting VPS in Island.
|
||
|
||
---
|
||
|
||
## VPS-Infrastruktur
|
||
|
||
| Eigenschaft | Wert |
|
||
| --------------- | ------------------------------------------------- |
|
||
| Anbieter | 1984 Hosting (1984.is), Reykjavik, Island |
|
||
| VPS-Name | vpshoxc2sc |
|
||
| IP | `195.246.231.210` |
|
||
| DNS PTR | vps-195-246-231-210.1984.is |
|
||
| OS | Debian 12 (Bookworm) |
|
||
| RAM | 1024 MB |
|
||
| CPU | 1 |
|
||
| Disk | 25 GB SSD |
|
||
| Transfer | 1 TB/Monat |
|
||
| Docker | Docker CE 29.x + docker-compose-plugin |
|
||
| App-Verzeichnis | `/opt/bollwerk/` |
|
||
|
||
---
|
||
|
||
## SSH-Zugang
|
||
|
||
```powershell
|
||
# Voraussetzung: SSH-Agent muss laufen und Key geladen sein
|
||
ssh root@195.246.231.210
|
||
```
|
||
|
||
### SSH-Agent starten (einmalig pro Windows-Session)
|
||
|
||
Der SSH-Key ist passphrase-geschützt. Der Agent muss laufen, damit Batch-Befehle funktionieren:
|
||
|
||
```powershell
|
||
# 1. Agent-Dienst starten (braucht ggf. Admin-Rechte beim ersten Mal)
|
||
Start-Service ssh-agent
|
||
|
||
# 2. Key laden (fragt einmalig nach der Passphrase)
|
||
ssh-add C:\Users\JensR\.ssh\id_ed25519
|
||
|
||
# Prüfen
|
||
ssh-add -l
|
||
```
|
||
|
||
**Wichtig:** Ohne geladenen SSH-Agent schlagen alle `ssh`/`scp`-Befehle mit `Permission denied (publickey)` fehl. Immer zuerst `ssh-add -l` prüfen.
|
||
|
||
### SSH-Key-Details
|
||
|
||
| Eigenschaft | Wert |
|
||
| ----------- | ------------------------------------------------------------- |
|
||
| Typ | Ed25519 (256 Bit) |
|
||
| Fingerprint | `SHA256:J/qjVt9r8CqnoshZFQWutau+3KG7JxDzRLHPyX41+gA` |
|
||
| Private Key | `C:\Users\JensR\.ssh\id_ed25519` (passphrase-geschützt) |
|
||
| Public Key | `C:\Users\JensR\.ssh\id_ed25519.pub` |
|
||
| Kommentar | `bollwerk-vps` |
|
||
|
||
---
|
||
|
||
## Deployment-Workflow
|
||
|
||
### Vollständiges Deployment (JAR neu bauen + hochladen)
|
||
|
||
```powershell
|
||
# 1. Fat-JAR lokal bauen
|
||
cd x:\bollwerk
|
||
.\gradlew.bat :server:buildFatJar
|
||
|
||
# 2. JAR auf VPS kopieren
|
||
scp x:\bollwerk\server\build\libs\server.jar root@195.246.231.210:/opt/bollwerk/server.jar
|
||
|
||
# 3. Container neu bauen und starten
|
||
ssh root@195.246.231.210 "cd /opt/bollwerk && docker compose up -d --build"
|
||
```
|
||
|
||
### Nur Container neustarten (ohne neues JAR)
|
||
|
||
```powershell
|
||
ssh root@195.246.231.210 "cd /opt/bollwerk && docker compose restart"
|
||
```
|
||
|
||
---
|
||
|
||
## Docker-Konfiguration auf dem VPS
|
||
|
||
### Dockerfile (`/opt/bollwerk/Dockerfile`)
|
||
|
||
```dockerfile
|
||
FROM eclipse-temurin:21-jre-alpine
|
||
WORKDIR /app
|
||
COPY server.jar server.jar
|
||
EXPOSE 8080
|
||
ENTRYPOINT ["java", "-Xmx384m", "-jar", "server.jar"]
|
||
```
|
||
|
||
**Hinweis:** `-Xmx384m` begrenzt den JVM-Heap, weil der VPS nur 1 GB RAM hat.
|
||
|
||
### docker-compose.yml (`/opt/bollwerk/docker-compose.yml`)
|
||
|
||
```yaml
|
||
services:
|
||
bollwerk:
|
||
build: .
|
||
container_name: bollwerk-server
|
||
restart: unless-stopped
|
||
ports:
|
||
- '8080:8080'
|
||
environment:
|
||
- BOLLWERK_JWT_SECRET=<secret>
|
||
volumes:
|
||
- ./data:/app/data
|
||
```
|
||
|
||
**Hinweis:** Das JWT-Secret NICHT in Skill-Dateien oder Git speichern. Es liegt nur in der `docker-compose.yml` auf dem VPS.
|
||
|
||
---
|
||
|
||
## Authentifizierung
|
||
|
||
Der Server nutzt JWT-basierte Authentifizierung (kein API-Key mehr).
|
||
|
||
### Admin-Zugang
|
||
|
||
- **Admin-UI:** `http://195.246.231.210:8080/admin/`
|
||
- **Admin-User:** `admin`
|
||
- **Admin-Passwort:** Der User muss das Passwort selbst eingeben. Es ist NICHT gespeichert – bei Bedarf den User fragen.
|
||
- Beim ersten Start ohne `BOLLWERK_ADMIN_PASSWORD` ENV wird ein zufälliges Passwort generiert und in die Logs geschrieben.
|
||
|
||
### Environment-Variablen
|
||
|
||
| Variable | Pflicht | Beschreibung |
|
||
| ------------------------------- | ------- | --------------------------------------------------- |
|
||
| `BOLLWERK_JWT_SECRET` | ja | Secret für JWT-Token-Signierung (mind. 32 Zeichen) |
|
||
| `BOLLWERK_ADMIN_PASSWORD` | nein | Admin-Passwort beim ersten Start (sonst auto-gen.) |
|
||
|
||
---
|
||
|
||
## Server-Endpunkte
|
||
|
||
| Endpunkt | Auth | Beschreibung |
|
||
| ------------------------------ | ----- | ------------------------------------- |
|
||
| `GET /api/health` | nein | Health-Check → "OK" |
|
||
| `POST /api/auth/login` | nein | Login → JWT (Access + Refresh Token) |
|
||
| `POST /api/auth/refresh` | nein | Access-Token erneuern |
|
||
| `GET /api/inventory` | JWT | Inventar des Users abrufen |
|
||
| `PUT /api/inventory` | JWT | Inventar des Users hochladen |
|
||
| `PATCH /api/inventory/items/{id}` | JWT | Einzelnen Artikel updaten |
|
||
| `GET /api/admin/users` | Admin | Alle User auflisten |
|
||
| `POST /api/admin/users` | Admin | Neuen User anlegen |
|
||
| `PUT /api/admin/users/{id}` | Admin | Passwort ändern |
|
||
| `DELETE /api/admin/users/{id}` | Admin | User löschen |
|
||
| `WS /ws/sync` | JWT | WebSocket für Push-Benachrichtigungen |
|
||
|
||
JWT wird als `Authorization: Bearer <accessToken>` Header mitgeschickt.
|
||
|
||
---
|
||
|
||
## Monitoring & Troubleshooting
|
||
|
||
### Container-Status prüfen
|
||
|
||
```powershell
|
||
ssh root@195.246.231.210 "docker ps"
|
||
```
|
||
|
||
### Logs anzeigen
|
||
|
||
```powershell
|
||
# Letzte 50 Zeilen
|
||
ssh root@195.246.231.210 "docker logs bollwerk-server --tail 50"
|
||
|
||
# Live-Logs (Ctrl+C zum Beenden)
|
||
ssh root@195.246.231.210 "docker logs bollwerk-server -f"
|
||
```
|
||
|
||
### Health-Check
|
||
|
||
```powershell
|
||
# Vom lokalen PC
|
||
Invoke-WebRequest -Uri "http://195.246.231.210:8080/api/health" -UseBasicParsing
|
||
|
||
# Auf dem VPS direkt
|
||
ssh root@195.246.231.210 "curl -s http://localhost:8080/api/health"
|
||
```
|
||
|
||
### Container stoppen/starten
|
||
|
||
```powershell
|
||
ssh root@195.246.231.210 "cd /opt/bollwerk && docker compose stop"
|
||
ssh root@195.246.231.210 "cd /opt/bollwerk && docker compose start"
|
||
ssh root@195.246.231.210 "cd /opt/bollwerk && docker compose down" # Container entfernen
|
||
```
|
||
|
||
### RAM-Nutzung prüfen
|
||
|
||
```powershell
|
||
ssh root@195.246.231.210 "free -h && echo '---' && docker stats --no-stream"
|
||
```
|
||
|
||
### Daten-Persistenz
|
||
|
||
Die SQLite-Datenbank wird unter `/opt/bollwerk/data/` auf dem Host gemountet und überlebt Container-Neustarts.
|
||
|
||
---
|
||
|
||
## Bekannte Einschränkungen
|
||
|
||
- **1 GB RAM:** JVM-Heap auf 384 MB begrenzt. Kein Spielraum für weitere Dienste.
|
||
- **Kein HTTPS:** Server läuft aktuell nur auf HTTP Port 8080. Für HTTPS → Caddy als Reverse Proxy einrichten.
|
||
- **Kein CI/CD:** Deployment ist manuell (JAR bauen → scp → docker compose up). Ggf. GitHub Actions Pipeline ergänzen.
|
||
- **Dockerfile lokal:** Das Dockerfile auf dem VPS (`/opt/bollwerk/Dockerfile`) ist ein schlankes Runtime-Only-Image. Das Multi-Stage-Dockerfile im Repo-Root ist für lokale Builds gedacht.
|
||
- **SSH-Escape-Problem:** Beim Schreiben von Dateien via SSH-Heredoc werden JSON-Quotes zerstört. Dateien immer lokal erstellen und per `scp` hochladen.
|