Lumio auf dem eigenen Server installieren.
Für Studios mit eigener Infrastruktur — Mini-PC, ausgemusterte Workstation, gemieteter Root-Server oder eigene VM. Der Stack ist derselbe wie überall; der eigene Dreh ist die Erreichbarkeit und wer sich um Backups kümmert (du).
Was du brauchst
Lumio ist ein reiner Docker-Compose-Stack und bringt alles mit (PostgreSQL, Redis, MinIO als Objektspeicher, Caddy, die App selbst). Er läuft auf so ziemlich jeder Linux-Maschine, wenn diese Punkte passen:
- 64-Bit-Linux (amd64 oder arm64) — Ubuntu 22.04 LTS oder Debian 12 sind typisch
- Docker ≥ 24 mit Compose v2 (
docker compose version) - RAM: nur Fotos ab 4 GB, mit Video 8 GB, KI-Tagging nochmal +4 GB
- Eine Domain und ein Plan, wie der Server erreichbar ist (nächster Abschnitt)
- Speicher für die Bilddaten — idealerweise gespiegelt (RAID) oder auf einem NAS
Zuerst klären — Erreichbarkeit & TLS
Das ist der Punkt, an dem sich on-premise von einem Cloud-Server unterscheidet. Kläre vor der Installation, welcher der beiden Fälle auf dich zutrifft:
Fall A — Server ist von außen erreichbar
Du hast eine öffentliche IP (fest oder per DynDNS nachgeführt) und kannst
die Ports 80 und 443 auf den Server weiterleiten. Dann holt sich Caddy
das Let's-Encrypt-Zertifikat automatisch — genau wie in der
Hetzner-Anleitung.
In der .env reicht:
LUMIO_HOST=fotos.deinstudio.de
PUBLIC_URL=https://fotos.deinstudio.de
S3_PUBLIC_URL=https://fotos.deinstudio.de/s3 Fall B — kein eingehender Port 80/443 (CGNAT, Firmen-LAN)
Dann terminierst du HTTPS außerhalb und leitest einfaches HTTP an Lumios Caddy weiter — über einen Tunnel (Cloudflare Tunnel, Tailscale Funnel) oder einen vorhandenen Reverse-Proxy. Caddy läuft dann nur auf einem HTTP-Port; das gültige Zertifikat bringt der Tunnel mit:
LUMIO_HOST=fotos.deinstudio.de
LUMIO_S3_HOST=s3.deinstudio.de
PUBLIC_URL=https://fotos.deinstudio.de
S3_PUBLIC_URL=https://s3.deinstudio.de
CADDY_HTTP_PORT=8080 # Tunnel/Proxy zeigt hierauf, TLS macht er selbst
Caddy vertraut X-Forwarded-Proto aus privaten Netzen und erkennt das extern terminierte HTTPS korrekt.
Schritt 1 — Server vorbereiten
Nicht-root-User, SSH per Key, Firewall, Docker. Kompakt — ausführlicher steht das in der Hetzner-Anleitung:
# System aktualisieren
sudo apt update && sudo apt upgrade -y
# Firewall — nur was nötig ist
sudo ufw allow OpenSSH
sudo ufw allow 80
sudo ufw allow 443
sudo ufw --force enable
# Docker-Engine + Compose-Plugin
curl -fsSL https://get.docker.com | sh
sudo usermod -aG docker $USER
# neu einloggen, damit die Gruppe greift, dann testen:
docker run --rm hello-world In Fall B (Tunnel) musst du 80/443 in der Firewall nicht öffnen — der Tunnel baut die Verbindung von innen auf.
Schritt 2 — Lumio holen & konfigurieren
sudo mkdir -p /opt/lumio && sudo chown $USER:$USER /opt/lumio
cd /opt/lumio
git clone https://github.com/markusthiel/lumio.git .
cp .env.example .env Sichere Secrets erzeugen:
sed -i "s|^POSTGRES_PASSWORD=.*|POSTGRES_PASSWORD=$(openssl rand -base64 24 | tr -d '/+=')|" .env
sed -i "s|^JWT_SECRET=.*|JWT_SECRET=$(openssl rand -base64 32 | tr -d '/+=')|" .env
sed -i "s|^SESSION_SECRET=.*|SESSION_SECRET=$(openssl rand -base64 32 | tr -d '/+=')|" .env
sed -i "s|^S3_ACCESS_KEY=.*|S3_ACCESS_KEY=$(openssl rand -hex 12)|" .env
sed -i "s|^S3_SECRET_KEY=.*|S3_SECRET_KEY=$(openssl rand -base64 32 | tr -d '/+=')|" .env
Dann Domain/TLS je nach Fall A oder B aus dem Abschnitt oben eintragen. DEPLOYMENT_MODE=single ist der Default — so lassen, das legt beim ersten Start automatisch ein Studio an.
Schritt 3 — Starten & Admin anlegen
# Stack starten (erster Start baut die Images, dauert etwas)
docker compose -f docker-compose.yml -f docker-compose.prod.yml up -d
docker compose ps # laufen alle Services?
docker compose logs -f # Logs verfolgen Ersten Benutzer anlegen:
docker compose exec api npm run create-admin \
-- --email=du@deinstudio.de --password=mind12zeichen
Studio-Login unter https://fotos.deinstudio.de. Fertig, wenn Test-Galerie anlegen, Bild hochladen, Link teilen und von einem anderen Gerät öffnen einmal durchläuft.
Schritt 4 — Betrieb: Backup & Updates
On-premise heißt: Backups sind komplett dein Job. Sichere die Datenbank und die Objektdaten regelmäßig — und kopiere sie an einen zweiten Ort außer Haus.
# Datenbank-Dump (z.B. täglich per Cron)
docker compose exec -T postgres pg_dump -U lumio lumio > backup_$(date +%F).sql
# Objektdaten liegen im Docker-Volume (MinIO) — mitsichern
docker volume ls | grep minio
# Update: neue Version holen und neu bauen
git pull
docker compose -f docker-compose.yml -f docker-compose.prod.yml up -d --build Häufige Fragen zum on-premise-Setup
Brauche ich eine feste öffentliche IP? +
Nein. Eine dynamische IP reicht, solange du eine Domain per DynDNS/DDNS nachführen lässt (viele Router können das, sonst Dienste wie deSEC oder Cloudflare). Wichtiger als eine feste IP ist, dass dein Server von außen auf Port 80/443 erreichbar ist — oder dass du einen Tunnel nutzt (siehe unten). Ganz ohne eingehende Erreichbarkeit geht es auch, dann terminierst du TLS an anderer Stelle.
Was, wenn ich Port 80/443 nicht öffnen kann oder darf (CGNAT, Firmen-LAN)? +
Dann terminierst du HTTPS außerhalb von Lumio und leitest einfaches HTTP an Lumios Caddy weiter. Bewährt: ein Tunnel wie Cloudflare Tunnel oder Tailscale Funnel, oder ein bereits vorhandener Reverse-Proxy. Lumios Caddy unterstützt diesen External-Reverse-Proxy-Modus ausdrücklich (LUMIO_HOST + LUMIO_S3_HOST setzen, Caddy nur auf einem HTTP-Port). Der Tunnel bringt das gültige Zertifikat mit — du musst gar nichts nach außen öffnen.
Kann ich Lumio nur im lokalen Netz (LAN) betreiben? +
Ja. Für ein gültiges HTTPS-Zertifikat braucht Let's Encrypt allerdings entweder öffentliche Erreichbarkeit (HTTP-Challenge) oder eine DNS-Challenge über deinen DNS-Anbieter. Rein im LAN ohne Internet bleibt der Weg über ein eigenes internes Zertifikat oder einen Tunnel. Für den Kunden-Versand von Galerie-Links ist echte Erreichbarkeit von außen aber ohnehin der Normalfall.
Welche Hardware sollte der Server haben? +
64-Bit-Linux (amd64 oder arm64), Docker ≥ 24 mit Compose v2. Faustregel RAM: nur Fotos ab 4 GB, mit Video-Transcoding 8 GB, optionales KI-Auto-Tagging nochmal +4 GB. Eine ausgemusterte Workstation oder ein kleiner Mini-PC reicht für ein Solo-Studio locker. Für die Bilddaten sinnvoll: gespiegelter Speicher (RAID) oder ein NAS-Mount, damit ein Plattenausfall dich nicht die Originale kostet.
Wie mache ich Backups, wenn niemand außer mir zuständig ist? +
Zwei Dinge sichern: die Postgres-Datenbank (täglicher pg_dump per Cron) und die Objektdaten (das MinIO-Volume). Beides regelmäßig an einen zweiten Ort außer Haus kopieren — anderer Datenträger, anderes Gebäude oder ein günstiger Object-Storage-Bucket bei einem Anbieter. On-premise heißt: die Sicherung liegt komplett bei dir, plane sie von Anfang an ein.
Bereit für deine eigene Galerie?
Source-Code auf GitHub, Fragen und Diskussionen ebenfalls dort. Wenn in der Anleitung etwas hakt, melde dich — wir verbessern die Docs gerne.