Medien-Stack: Fivemanage Lite mit MySQL und MinIO

Ein Ablageort fuer alle Resourcen statt Nextcloud plus rclone von Hand. Der
Unterschied ist nicht der Speicher — den gibt es schon — sondern ein
Schreibweg ueber HTTP: sobald ein Script hochladen soll, fehlt er, und Lite
bringt ihn mit, samt Token je Resource und einer Oberflaeche zum Nachsehen.

Zusammengestellt aus fivemanage/lite: dessen README, der
deployments/docker-compose.yml (Entwicklung, startet die App gar nicht) und der
deployments/docker-compose.test.yml (zeigt die App-Verdrahtung und dass MySQL
genuegt und ClickHouse nicht Pflicht ist).

Zwei Fassungen, und der Unterschied ist Absicht:

  docker-compose.yml         fuer den Betrieb ueber Portainer aus diesem Repo.
                             Keine offenen Ports, nur der Reverse Proxy
                             spricht mit der App.
  docker-compose.local.yml   zum Ausprobieren auf Docker Desktop. Ports offen,
                             kein Proxy. Eine beta.23 gehoert erst auf einen
                             Rechner, an dem nichts haengt.

Ohne ClickHouse und Jaeger: beides ist Logging und Tracing, fuer das Ablegen
von Bildern nicht noetig, und ClickHouse ist eine schwere Abhaengigkeit.

Ein Init-Container legt den Bucket an und stellt ihn auf oeffentlich lesbar.
Ohne diesen Schritt schlaegt der erste Upload fehl, und die Meldung nennt den
Grund nicht.

Healthchecks mit depends_on/condition, sonst startet die App gegen eine
Datenbank, die noch nicht antwortet, und beendet sich — beim ersten Hochfahren
jedes Mal.

NICHT laufen gelassen: Docker war von hier nicht erreichbar. Das YAML ist
geprueft, das Compose-Schema nicht.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
2026-08-11 14:06:21 +02:00
co-authored by Claude Opus 5
commit 72f61dbd07
5 changed files with 313 additions and 0 deletions
+24
View File
@@ -0,0 +1,24 @@
# Fivemanage Lite — Geheimnisse und Adressen
#
# Diese Datei ist die VORLAGE. Kopiere sie nach .env und trag echte Werte ein.
# .env selbst gehoert nicht ins Repo (siehe .gitignore).
#
# In Portainer traegst du dieselben Werte stattdessen als Stack-Variablen ein;
# dann braucht es die Datei dort gar nicht.
#
# Erzeugen:
# openssl rand -hex 16 DB_PASSWORD, MINIO_ROOT_PASSWORD
# openssl rand -hex 32 API_TOKEN_HMAC_SECRET (muss 32 Byte sein)
# openssl rand -hex 12 ADMIN_PASSWORD
DB_PASSWORD=
MINIO_ROOT_PASSWORD=
API_TOKEN_HMAC_SECRET=
ADMIN_PASSWORD=
# Unter welcher Adresse die Dateien oeffentlich liegen. Ohne sie liefert MinIO
# Links auf den internen Containernamen aus — die gehen von aussen ins Leere.
PUBLIC_URL=https://fivecdn.d4rkst3r.de
# Das Docker-Netz, in dem der bestehende Reverse Proxy haengt.
PROXY_NETWORK=proxy
+2
View File
@@ -0,0 +1,2 @@
# Die echten Geheimnisse. Nur .env.example gehoert ins Repo.
.env
+84
View File
@@ -0,0 +1,84 @@
# 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`.
Davor brauchst du auf dem Reverse Proxy, der schon `cdn.d4rkst3r.de` bedient:
- `fivecdn.d4rkst3r.de``minio:9000` (die Dateien)
- eine zweite Adresse → `lite:8080` (die Oberfläche), oder gar nicht öffentlich
---
## Die vier Geheimnisse
```bash
openssl rand -hex 16 # DB_PASSWORD
openssl rand -hex 16 # MINIO_ROOT_PASSWORD
openssl rand -hex 32 # API_TOKEN_HMAC_SECRET (muss 32 Byte sein)
openssl rand -hex 12 # ADMIN_PASSWORD
```
---
## 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.
+90
View File
@@ -0,0 +1,90 @@
# Zum Ausprobieren auf Docker Desktop.
#
# Der Unterschied zur Betriebsfassung ist Absicht und in beide Richtungen:
# hier sind die Ports offen und es gibt keinen Reverse Proxy, dort ist es
# umgekehrt. Eine `beta.23` gehoert erst auf einen Rechner, an dem nichts
# haengt — und wenn sie dort traegt, auf den Server.
#
# docker compose -f docker-compose.local.yml up -d
#
# Danach: http://localhost:8080 (admin / ADMIN_PASSWORD aus .env)
# http://localhost:9001 (MinIO, lite / MINIO_ROOT_PASSWORD)
services:
db:
image: mysql:8
environment:
MYSQL_DATABASE: fivemanage_lite
MYSQL_USER: lite
MYSQL_PASSWORD: ${DB_PASSWORD:?bitte setzen}
MYSQL_RANDOM_ROOT_PASSWORD: "yes"
volumes:
- db:/var/lib/mysql
healthcheck:
test: ["CMD", "mysqladmin", "ping", "-h", "localhost"]
interval: 5s
timeout: 5s
retries: 20
minio:
image: minio/minio:latest
command: server /data --console-address ":9001"
environment:
MINIO_ROOT_USER: lite
MINIO_ROOT_PASSWORD: ${MINIO_ROOT_PASSWORD:?bitte setzen}
# Oertlich: die Dateien liegen unter derselben Adresse, unter der MinIO
# antwortet. Erst auf dem Server tritt fivecdn.d4rkst3r.de an die Stelle.
MINIO_SERVER_URL: http://localhost:9000
ports:
- "9000:9000"
- "9001:9001"
volumes:
- minio:/data
healthcheck:
test: ["CMD", "mc", "ready", "local"]
interval: 5s
timeout: 5s
retries: 20
minio-init:
image: minio/mc:latest
depends_on:
minio:
condition: service_healthy
environment:
MINIO_ROOT_PASSWORD: ${MINIO_ROOT_PASSWORD:?bitte setzen}
entrypoint: >
/bin/sh -c "
mc alias set local http://minio:9000 lite $$MINIO_ROOT_PASSWORD &&
mc mb --ignore-existing local/media &&
mc anonymous set download local/media &&
echo 'Bucket media ist bereit'
"
restart: "no"
lite:
image: fivemanage/lite:0.1.0-beta.23
depends_on:
db:
condition: service_healthy
minio:
condition: service_healthy
environment:
PORT: "8080"
ENV: dev
DB_DRIVER: mysql
DSN: lite:${DB_PASSWORD:?bitte setzen}@tcp(db:3306)/fivemanage_lite
ADMIN_PASSWORD: ${ADMIN_PASSWORD:?bitte setzen}
API_TOKEN_HMAC_SECRET: ${API_TOKEN_HMAC_SECRET:?bitte setzen}
S3_PROVIDER: minio
AWS_ENDPOINT: http://minio:9000
AWS_ACCESS_KEY_ID: lite
AWS_SECRET_ACCESS_KEY: ${MINIO_ROOT_PASSWORD:?bitte setzen}
AWS_BUCKET: media
AWS_REGION: auto
ports:
- "8080:8080"
volumes:
db:
minio:
+113
View File
@@ -0,0 +1,113 @@
# Fivemanage Lite — fuer den Betrieb, ueber Portainer aus diesem Repo.
#
# Abgeleitet aus den beiden Compose-Dateien im Projekt (fivemanage/lite) und
# dem README. Deren docker-compose.yml ist fuer die ENTWICKLUNG: sie startet
# Datenbank, ClickHouse, MinIO und Jaeger, aber nicht die Anwendung, und mit
# Standardpasswoertern. Die docker-compose.test.yml zeigt dafuer, wie der
# App-Container verdrahtet wird — und dass MySQL genuegt.
#
# Bewusst NICHT dabei:
#
# ClickHouse und Jaeger. Beides ist strukturiertes Logging und Tracing. Fuer
# das Ablegen von Bildern braucht es sie nicht, und ClickHouse ist eine
# schwere Abhaengigkeit. Nachruesten geht spaeter.
#
# Offene Ports. Nur der Reverse Proxy spricht mit der App; Datenbank und
# MinIO bleiben im internen Netz. Zum Ausprobieren gibt es
# docker-compose.local.yml — die macht es andersherum, und dort ist es
# richtig.
services:
db:
image: mysql:8
restart: unless-stopped
environment:
MYSQL_DATABASE: fivemanage_lite
MYSQL_USER: lite
MYSQL_PASSWORD: ${DB_PASSWORD:?bitte in .env oder als Stack-Variable setzen}
MYSQL_RANDOM_ROOT_PASSWORD: "yes"
volumes:
- db:/var/lib/mysql
networks: [internal]
healthcheck:
# Ohne das startet die App gegen eine Datenbank, die noch nicht
# antwortet, und beendet sich — beim ersten Hochfahren jedes Mal.
test: ["CMD", "mysqladmin", "ping", "-h", "localhost"]
interval: 10s
timeout: 5s
retries: 12
minio:
image: minio/minio:latest
restart: unless-stopped
command: server /data --console-address ":9001"
environment:
MINIO_ROOT_USER: lite
MINIO_ROOT_PASSWORD: ${MINIO_ROOT_PASSWORD:?bitte setzen}
MINIO_SERVER_URL: ${PUBLIC_URL:?bitte setzen}
volumes:
- minio:/data
networks: [internal, proxy]
healthcheck:
test: ["CMD", "mc", "ready", "local"]
interval: 10s
timeout: 5s
retries: 12
# Legt den Bucket an und stellt ihn auf oeffentlich lesbar. Laeuft einmal und
# beendet sich. Ohne diesen Schritt schlaegt der erste Upload fehl, und die
# Meldung nennt den Grund nicht.
minio-init:
image: minio/mc:latest
depends_on:
minio:
condition: service_healthy
environment:
MINIO_ROOT_PASSWORD: ${MINIO_ROOT_PASSWORD:?bitte setzen}
entrypoint: >
/bin/sh -c "
mc alias set local http://minio:9000 lite $$MINIO_ROOT_PASSWORD &&
mc mb --ignore-existing local/media &&
mc anonymous set download local/media &&
echo 'Bucket media ist bereit'
"
networks: [internal]
restart: "no"
lite:
image: fivemanage/lite:0.1.0-beta.23
restart: unless-stopped
depends_on:
db:
condition: service_healthy
minio:
condition: service_healthy
environment:
PORT: "8080"
ENV: production
DB_DRIVER: mysql
# Go-MySQL-Form, wie in deren docker-compose.test.yml.
DSN: lite:${DB_PASSWORD:?bitte setzen}@tcp(db:3306)/fivemanage_lite
ADMIN_PASSWORD: ${ADMIN_PASSWORD:?bitte setzen}
API_TOKEN_HMAC_SECRET: ${API_TOKEN_HMAC_SECRET:?bitte setzen}
S3_PROVIDER: minio
AWS_ENDPOINT: http://minio:9000
AWS_ACCESS_KEY_ID: lite
AWS_SECRET_ACCESS_KEY: ${MINIO_ROOT_PASSWORD:?bitte setzen}
AWS_BUCKET: media
AWS_REGION: auto
networks: [internal, proxy]
# KEIN ports: — der Reverse Proxy erreicht die App ueber das Netz `proxy`.
# Wer hier 8080 aufmacht, hat die Oberflaeche ohne TLS im Internet.
networks:
internal:
driver: bridge
proxy:
# Das Netz, in dem der bestehende Reverse Proxy haengt.
name: ${PROXY_NETWORK:-proxy}
external: true
volumes:
db:
minio: