Der Stack lief, meldete alle Container gesund — und beide Adressen gaben 502. Grund: kein einziger Port veroeffentlicht. Die standen in docker-compose.hostports.yml, und Portainer hat die nicht angewandt. Das war mein Anleitungsfehler. Ich hatte geschrieben, man koenne unter "Compose path" zwei Pfade mit Komma angeben. Portainer nimmt dort EINE Datei. Die Ergaenzung wurde nicht etwa abgelehnt, sondern stillschweigend ignoriert — die schlechteste Art zu scheitern, weil danach alles gesund aussieht. Eine Trennung, die man nicht anwenden kann, ist keine. Die Ports stehen jetzt in docker-compose.yml, wo dieser Server sie ohnehin braucht. docker-compose.proxynet.yml bleibt als der sauberere Weg fuer einen Proxy im selben Docker-Netz, jetzt aber mit dem Hinweis, dass er ueber Portainer-aus- Repo nicht zu haben ist. Hier trifft er nicht zu: NPM liegt auf 172.17.0.3 im Standard-Bridge-Netz. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
197 lines
7.2 KiB
Markdown
197 lines
7.2 KiB
Markdown
# d4rk_media
|
||
|
||
Der Medien-Stack: **Fivemanage Lite** mit MySQL und MinIO. Ein Ablageort für
|
||
alle Resourcen — Fahrzeugbilder aus `d4rk_photostudio`, Item-Icons, Marken,
|
||
was sonst noch anfällt.
|
||
|
||
Bisher liegt das auf dem Nextcloud und wird per rclone von Hand hochgeladen.
|
||
Das trägt, solange ein Mensch hochlädt. Sobald ein Script es tun soll, fehlt
|
||
ein Schreibweg über HTTP — und genau den bringt Lite mit, samt Token je
|
||
Resource und einer Oberfläche zum Nachsehen.
|
||
|
||
---
|
||
|
||
## Ausprobieren, bevor es auf den Server geht
|
||
|
||
`0.1.0-beta.23` ist früh. Erst auf Docker Desktop:
|
||
|
||
```bash
|
||
cp .env.example .env # und ausfüllen, siehe unten
|
||
docker compose -f docker-compose.local.yml up -d
|
||
```
|
||
|
||
- Oberfläche: <http://localhost:8080> — `admin` und dein `ADMIN_PASSWORD`
|
||
- MinIO: <http://localhost:9001> — `lite` und dein `MINIO_ROOT_PASSWORD`
|
||
|
||
Wenn das trägt, dasselbe auf dem Server.
|
||
|
||
---
|
||
|
||
## Auf dem Server, über Portainer
|
||
|
||
Portainer kann einen Stack direkt aus diesem Repo ziehen:
|
||
|
||
**Stacks → Add stack → Repository**
|
||
|
||
| Feld | Wert |
|
||
|---|---|
|
||
| Repository URL | `https://git.d4rkst3r.de/D4rkst3r/d4rk_media` |
|
||
| Compose path | `docker-compose.yml` |
|
||
| Environment variables | die vier Geheimnisse plus `PUBLIC_URL` |
|
||
|
||
Die Werte gehören **in die Stack-Variablen**, nicht in eine Datei im Repo.
|
||
`.env` steht deshalb in `.gitignore`.
|
||
|
||
### Wie der Reverse Proxy die Dienste erreicht
|
||
|
||
Über den **Host**, und das steht fertig in `docker-compose.yml`. Genauso laufen
|
||
`d4rkbot` auf 3080 und `cdn-files` auf 8090 schon.
|
||
|
||
```
|
||
fivecdn.d4rkst3r.de -> http://host.docker.internal:9100
|
||
fivemanage.d4rkst3r.de -> http://host.docker.internal:9101
|
||
```
|
||
|
||
**Nicht 9000 und 8080** — die sind auf diesem Server vergeben (Portainer und
|
||
nextcloud-aio). Im Container bleibt es bei 9000 und 8080; nur die Seite zum
|
||
Host wandert. Kollidiert später noch etwas, sind es zwei Variablen:
|
||
`MINIO_HOST_PORT` und `LITE_HOST_PORT`.
|
||
|
||
Die Ports sind an **alle** Adressen gebunden, nicht an `127.0.0.1`. Das ist
|
||
kein Versehen: NPM liegt im Standard-Bridge-Netz (`172.17.0.3`) und kommt über
|
||
die Docker-Brücke herein, nicht über Loopback — ein an `127.0.0.1` gebundener
|
||
Port nimmt diese Anfrage nicht an. **Zu macht sie die Firewall**, nicht die
|
||
Bindung. 9100 und 9101 gehören von außen dicht; öffentlich soll nur NPM auf
|
||
80/443 sein.
|
||
|
||
#### Wenn der Proxy im selben Docker-Netz hängt
|
||
|
||
Dann geht es sauberer, ganz ohne offene Ports — dafür liegt
|
||
`docker-compose.proxynet.yml` bereit. **Portainer nimmt unter *Compose path*
|
||
aber nur eine Datei**; eine Ergänzung wird dort stillschweigend ignoriert. Wer
|
||
diesen Weg will, führt die beiden Dateien zusammen oder startet den Stack von
|
||
Hand:
|
||
|
||
```bash
|
||
docker compose -f docker-compose.yml -f docker-compose.proxynet.yml up -d
|
||
```
|
||
|
||
Auf **diesem** Server trifft das nicht zu.
|
||
|
||
Die Ports sind an **alle Adressen** gebunden, weil `host.docker.internal` auf
|
||
diesem Server über die Docker-Brücke kommt und ein `127.0.0.1`-Port die
|
||
Anfrage nicht annähme — dieselbe Bindung, mit der `d4rkbot` und `cdn-files`
|
||
schon laufen.
|
||
|
||
**Damit macht die Firewall den Port zu, nicht die Bindung.** 9100 und 9101
|
||
gehören von außen dicht; öffentlich erreichbar soll nur NPM auf 80 und 443
|
||
sein. Wer weiß, dass Loopback bei ihm erreicht wird, setzt
|
||
`BIND_ADDR=127.0.0.1`.
|
||
|
||
---
|
||
|
||
## Die vier Geheimnisse
|
||
|
||
Sie werden **erzeugt**, nicht irgendwo abgeholt. Das Token für die Resourcen
|
||
kommt später und woanders her: aus der laufenden Lite-Oberfläche.
|
||
|
||
**PowerShell** — schreibt die fertige `.env`:
|
||
|
||
```powershell
|
||
function New-Secret([int]$n){ $b = New-Object byte[] $n; [System.Security.Cryptography.RandomNumberGenerator]::Create().GetBytes($b); ($b | ForEach-Object { $_.ToString('x2') }) -join '' }
|
||
@("DB_PASSWORD=$(New-Secret 16)","MINIO_ROOT_PASSWORD=$(New-Secret 16)","API_TOKEN_HMAC_SECRET=$(New-Secret 32)","ADMIN_PASSWORD=$(New-Secret 12)","PUBLIC_URL=https://fivecdn.d4rkst3r.de","PROXY_NETWORK=web") | Set-Content -Encoding ascii .env
|
||
```
|
||
|
||
Zwei Fallen stecken darin, beide schon hineingetreten:
|
||
|
||
- `RandomNumberGenerator::Create()` und **nicht** `::Fill` — letzteres gibt es
|
||
erst ab .NET 6, Windows PowerShell 5.1 kennt es nicht.
|
||
- `-Encoding ascii` und **nicht** `utf8` — PowerShell 5.1 schreibt sonst ein
|
||
BOM voran, und dann heißt die erste Variable `DB_PASSWORD`.
|
||
- `Get-Random` wäre die naheliegende Wahl und die falsche: es ist nicht
|
||
kryptografisch sicher, und hier wird ein Token-Signaturgeheimnis erzeugt.
|
||
|
||
**Bash / Linux:**
|
||
|
||
```bash
|
||
printf 'DB_PASSWORD=%s
|
||
MINIO_ROOT_PASSWORD=%s
|
||
API_TOKEN_HMAC_SECRET=%s
|
||
ADMIN_PASSWORD=%s
|
||
PUBLIC_URL=https://fivecdn.d4rkst3r.de
|
||
PROXY_NETWORK=proxy
|
||
' "$(openssl rand -hex 16)" "$(openssl rand -hex 16)" "$(openssl rand -hex 32)" "$(openssl rand -hex 12)" > .env
|
||
```
|
||
|
||
---
|
||
|
||
## PostgreSQL, nicht MySQL
|
||
|
||
`0.1.0-beta.23` geht direkt in den PostgreSQL-Treiber; `DB_DRIVER` wird nicht
|
||
ausgewertet. Eine MySQL-DSN endet deshalb in
|
||
|
||
```
|
||
panic: pgdriver: invalid scheme: lite
|
||
```
|
||
|
||
— der Treiber liest sie als URI und findet als Schema den Benutzernamen.
|
||
|
||
Die `docker-compose.test.yml` des Projekts zeigt MySQL, benutzt dafür aber
|
||
`fivemanage/lite:latest` von Docker Hub, und die Reihe steht dort bei
|
||
`beta.16` still. Das README des Projekts hat recht: `postgres://…`.
|
||
|
||
Das Volume heißt deshalb `pgdata` und nicht `db` — wer den Stack schon mit
|
||
MySQL laufen hatte, bekommt so eine frische Ablage, statt dass PostgreSQL über
|
||
ein MySQL-Verzeichnis stolpert. Das alte Volume bleibt als Waise liegen und
|
||
kann weg:
|
||
|
||
```bash
|
||
docker volume rm fivemanager_db
|
||
```
|
||
|
||
---
|
||
|
||
## Zwei Adressen, nicht eine
|
||
|
||
Lite spricht MinIO unter zwei verschiedenen Namen an, und beide muessen
|
||
stimmen:
|
||
|
||
| Variable | Wert | Wofuer |
|
||
|---|---|---|
|
||
| `AWS_ENDPOINT` | `http://minio:9000` | Wie Lite die Dateien **hinlegt** — Containername im internen Netz |
|
||
| `BUCKET_DOMAIN` | `$PUBLIC_URL/media` | Woraus die **oeffentliche** Adresse gebaut wird, die Lite nach dem Upload zurueckgibt |
|
||
|
||
`BUCKET_DOMAIN` steht nicht im README des Projekts, nur in dessen
|
||
`.env.template`. Ohne sie kaemen Adressen zurueck, die nur innerhalb von
|
||
Docker gelten — der Upload saehe erfolgreich aus, und das Bild waere von
|
||
aussen nicht abrufbar.
|
||
|
||
Den Bucket legt Lite beim Start selbst an und setzt dabei die oeffentliche
|
||
Leserichtlinie (`pkg/storage/s3/s3.go`). Es ueberspringt beides, wenn der
|
||
Bucket schon existiert — deshalb legt dieser Stack ihn **nicht** vorher an.
|
||
|
||
---
|
||
|
||
## Was hier bewusst fehlt
|
||
|
||
**ClickHouse und Jaeger.** Beide stehen in der Entwicklungs-Compose des
|
||
Projekts und sind für strukturiertes Logging und Tracing da. Zum Ablegen von
|
||
Bildern braucht es sie nicht, und ClickHouse ist eine schwere Abhängigkeit.
|
||
Nachrüsten geht jederzeit — die App findet sie über `CLICKHOUSE_*`.
|
||
|
||
**Offene Ports in der Betriebsfassung.** Nur der Reverse Proxy spricht mit der
|
||
App; Datenbank und MinIO bleiben im internen Netz. Die Entwicklungs-Compose des
|
||
Projekts macht 5432, 9000, 16686 und mehr auf — dort in Ordnung, hier nicht.
|
||
|
||
---
|
||
|
||
## Herkunft
|
||
|
||
Zusammengestellt aus [fivemanage/lite](https://github.com/fivemanage/lite):
|
||
dessen `README.md`, `deployments/docker-compose.yml` (Entwicklung, ohne die
|
||
App) und `deployments/docker-compose.test.yml` (zeigt die App-Verdrahtung und
|
||
dass MySQL genügt).
|
||
|
||
**Nicht laufen gelassen.** Rechne mit ein, zwei Anläufen — vor allem beim
|
||
ersten Login und beim Bucket.
|