Wer seine Fotos und Videos selbst hosten möchte, ohne ein Vermögen für Cloud-Speicher auszugeben, kommt an Immich kaum vorbei. Immich ist eine quelloffene Alternative zu Google Photos – mit automatischer Gesichtserkennung, Geodaten-Anzeige, Duplikaterkennung und vielem mehr. In diesem Artikel zeige ich, wie man Immich auf einem Hetzner Cloud VPS in Kombination mit einer Hetzner Storage Box betreibt.
Warum Hetzner?
Hetzner bietet vergleichsweise niedrige Preise für Cloud-Infrastruktur in Europa. Im Gegensatz zu Hyperscalern wie AWS, Azure oder Google Cloud gibt es:
- Feste Preise ohne versteckte Egress-Traffic-Kosten
- DSGVO-konformes Hosting mit Rechenzentren in Deutschland und Finnland
- Inklusiv-Traffic bei allen Cloud-Servern
- Storage Boxes mit Samba/CIFS-, SSH- und WebDAV-Zugriff, die sich für Immich eignen
Kostenübersicht
Variante 1: Minimales Setup (ab ~9,15 €/Monat)
| Komponente | Produkt | Kosten |
|---|---|---|
| VPS | CX22 (2 vCPU, 4 GB RAM, 40 GB SSD) | 5,34 €/Monat |
| Speicher | Storage Box BX11 (1 TB) | 3,81 €/Monat |
| Gesamt | ~9,15 €/Monat |
Dieses Setup reicht für Einsteiger mit einer kleineren Foto-Bibliothek (bis ca. 50.000 Fotos) völlig aus.
Variante 2: Mein Setup (~21,46 €/Monat für 5 TB)
| Komponente | Produkt | Kosten |
|---|---|---|
| VPS | CX32 (4 vCPU, 8 GB RAM, 80 GB SSD) | 7,13 €/Monat |
| Speicher | Storage Box BX21 (5 TB) | 12,97 €/Monat |
| SSD Volume | 20 GB für Thumbnail-Cache | 1,36 €/Monat |
| Gesamt | ~21,46 €/Monat |
Der größere VPS lohnt sich, da Immich gerade beim Machine Learning (Gesichtserkennung, CLIP-Suche) deutlich von mehr RAM profitiert. Das separate SSD-Volume für den Thumbnail-Cache sorgt für schnelle Ladezeiten in der App.
Storage-Architektur
Der Schlüssel zum kostengünstigen Betrieb ist die Trennung von schnellem und günstigem Speicher:
┌─────────────────────────────────────────────────────┐
│ Hetzner Cloud VPS │
│ │
│ ┌─────────────────────────────────────────────┐ │
│ │ Lokale SSD (im VPS enthalten) │ │
│ │ └── PostgreSQL-Datenbank │ │
│ └─────────────────────────────────────────────┘ │
│ │
│ ┌─────────────────────────────────────────────┐ │
│ │ SSD Volume (20 GB, optional) │ │
│ │ └── /data/thumbs (Thumbnail-Cache) │ │
│ └─────────────────────────────────────────────┘ │
│ │
│ ┌─────────────────────────────────────────────┐ │
│ │ CIFS Mount (1 Docker Volume) │ │
│ │ └── /data/upload (Subpath) │ │
│ │ └── /data/library (Subpath) │ │
│ │ └── /data/encoded-video (Subpath) │ │
│ │ └── /data/backups (Subpath) │ │
│ │ └── /data/profile (Subpath) │ │
│ └──────────────────┬──────────────────────────┘ │
└──────────────────────┼──────────────────────────────┘
│
▼
┌─────────────────────────┐
│ Hetzner Storage Box │
│ (1 TB / 5 TB / ...) │
│ via Samba/CIFS │
└─────────────────────────┘
Design-Entscheidungen
Warum Thumbnails auf SSD?
Thumbnails werden bei jedem Öffnen der App geladen. Liegen sie auf der Storage Box (Netzwerkspeicher), ist die Ladezeit spürbar langsamer. Ein kleines 20-GB-SSD-Volume für /data/thumbs sorgt für eine reaktionsschnelle Benutzeroberfläche.
Warum Medien auf der Storage Box? Originalfotos und -videos werden seltener direkt abgerufen. Die Storage Box kostet ca. 2,59 €/TB/Monat (bei BX21) und eignet sich für die Langzeitspeicherung großer Medienbibliotheken.
Warum die Datenbank auf der lokalen SSD? PostgreSQL benötigt schnelle I/O-Operationen. Ein Betrieb auf dem Netzwerkspeicher wäre extrem langsam und ist nicht empfehlenswert.
Schritt-für-Schritt-Anleitung
1. Hetzner Cloud Server erstellen
- Melde dich bei der Hetzner Console an
- Erstelle einen neuen Cloud Server:
W - Image: Ubuntu 24.04
- Typ: CX22 (minimal) oder CX32 (empfohlen)
- Optional: Erstelle ein Volume (20 GB) für den Thumbnail-Cache und hänge es an den Server
2. Storage Box bestellen
- In der Hetzner Console eine Storage Box bestellen (BX11 für 1 TB oder BX21 für 5 TB)
- Samba/CIFS aktivieren: In der Storage Box-Verwaltung unter “Einstellungen” das Samba-Protokoll aktivieren
- Zugangsdaten notieren (Benutzername, Passwort, Server-Adresse)
Wichtig: Server und Storage Box sollten im gleichen Rechenzentrum liegen, damit der interne Traffic kostenlos bleibt und die Latenz minimal ist.
docker-compose.yml
name: immich
services:
immich-server:
container_name: immich_server
image: ghcr.io/immich-app/immich-server:${IMMICH_VERSION:-release}
volumes:
# Medien auf der Storage Box via CIFS
- type: volume
source: immich_smb
target: /data/upload
volume:
subpath: upload
- type: volume
source: immich_smb
target: /data/encoded-video
volume:
subpath: encoded-video
- type: volume
source: immich_smb
target: /data/library
volume:
subpath: library
- type: volume
source: immich_smb
target: /data/backups
volume:
subpath: backups
- type: volume
source: immich_smb
target: /data/profile
volume:
subpath: profile
# Thumbnails auf schneller SSD
- /mnt/volume-hel1-1/immich/thumbs:/data/thumbs
- /etc/localtime:/etc/localtime:ro
env_file:
- stack.env
ports:
- '2283:2283'
depends_on:
- redis
- database
restart: always
healthcheck:
disable: false
labels:
- traefik.enable=true
- traefik.docker.network=traefik
- traefik.http.routers.immich.rule=Host(`immich.example.com`)
- traefik.http.routers.immich.entrypoints=websecure
- traefik.http.routers.immich.tls.certresolver=myresolver
- traefik.http.services.immich.loadbalancer.server.port=2283
networks:
- immich
- traefik
immich-machine-learning:
container_name: immich_machine_learning
image: ghcr.io/immich-app/immich-machine-learning:${IMMICH_VERSION:-release}
volumes:
- model-cache:/cache
env_file:
- stack.env
restart: always
healthcheck:
disable: false
networks:
- immich
redis:
container_name: immich_redis
image: docker.io/valkey/valkey:9
healthcheck:
test: redis-cli ping || exit 1
restart: always
networks:
- immich
database:
container_name: immich_postgres
image: ghcr.io/immich-app/postgres:14-vectorchord0.4.3-pgvectors0.2.0
environment:
POSTGRES_PASSWORD: ${DB_PASSWORD}
POSTGRES_USER: ${DB_USERNAME}
POSTGRES_DB: ${DB_DATABASE_NAME}
POSTGRES_INITDB_ARGS: '--data-checksums'
volumes:
- ${DB_DATA_LOCATION}:/var/lib/postgresql/data
shm_size: 128mb
restart: always
healthcheck:
disable: false
networks:
- immich
volumes:
immich_smb:
driver: local
driver_opts:
type: cifs
o: username=${SMB_USERNAME},password=${SMB_PASSWORD},vers=3.0,addr=${SMB_SERVER}
device: //${SMB_SERVER}/${SMB_SHARE}
model-cache:
networks:
immich:
internal: false
traefik:
external: true
So funktioniert die Storage-Box-Einbindung
Der entscheidende Teil ist das Docker Volume immich_smb. Es nutzt den local-Treiber mit CIFS-Optionen, um die Hetzner Storage Box als Netzlaufwerk einzubinden:
volumes:
immich_smb:
driver: local
driver_opts:
type: cifs
o: username=${SMB_USERNAME},password=${SMB_PASSWORD},vers=3.0,addr=${SMB_SERVER}
device: //${SMB_SERVER}/${SMB_SHARE}
Über subpath im Service werden die einzelnen Immich-Verzeichnisse (upload, library, encoded-video, backups, profile) als Unterordner auf der Storage Box abgebildet:
volumes:
- type: volume
source: immich_smb
target: /data/upload
volume:
subpath: upload
Damit werden alle Medien automatisch auf der Storage Box gespeichert, während der Container selbst nur wenig lokalen Speicher benötigt.
Wichtig: Die Hetzner Storage Box erlaubt maximal 10 gleichzeitige Verbindungen. Deshalb wird hier bewusst nur ein einziges Docker Volume (
immich_smb) per CIFS gemountet und die verschiedenen Verzeichnisse übersubpathabgebildet. Würde man für jedes Verzeichnis ein eigenes CIFS-Volume anlegen, wären die Verbindungen schnell aufgebraucht.
5. Umgebungsvariablen konfigurieren
Erstelle die Datei stack.env:
# Immich Version (leer = latest release)
IMMICH_VERSION=release
# Datenbank
DB_PASSWORD=<sicheres-passwort-generieren>
DB_USERNAME=immich
DB_DATABASE_NAME=immich
DB_DATA_LOCATION=/opt/immich/postgres
# Storage Box Samba-Zugangsdaten
SMB_USERNAME=<dein-storagebox-user>
SMB_PASSWORD=<dein-storagebox-passwort>
SMB_SERVER=<deine-storagebox>.your-storagebox.de
SMB_SHARE=backup
Performance-Tipps
Thumbnail-Cache auf SSD
Der Thumbnail-Cache ist der wichtigste Performance-Faktor. In der docker-compose.yml wird er direkt auf das SSD-Volume gemountet:
- /mnt/volume-hel1-1/immich/thumbs:/data/thumbs
Das Hetzner Volume (SSD) hat niedrigere Latenz als die Storage Box über das Netzwerk. Das Volume kann im laufenden Betrieb über die Hetzner Cloud-Oberfläche vergrößert werden – ein Herunterfahren des Servers ist dafür nicht nötig.
Hilfreiche Debug-Befehle
Um zu prüfen, ob die gemounteten Verzeichnisse korrekt eingebunden sind, kann man direkt in den Container schauen:
# Inhalt des Library-Verzeichnisses anzeigen
docker exec immich_server ls "/data/library/"
# Upload-Verzeichnis prüfen
docker exec immich_server ls "/data/upload/"
# Thumbnail-Verzeichnis prüfen
docker exec immich_server ls "/data/thumbs/"
# Speicherplatz der gemounteten Volumes anzeigen
docker exec immich_server df -h /data/
Migration großer Foto-Sammlungen via Synology NAS
Wer große Datenmengen an Bildern migrieren möchte, kann diese über ein Synology NAS per Cloud Sync via WebDAV auf die Hetzner Storage Box synchronisieren. Da die Daten dann bereits auf der Storage Box liegen, kann Immich sie direkt über die External Library-Funktion einlesen – das spart den langsamen Upload über das Internet.
Import mit immich-go
immich-go ist eine Alternative zur offiziellen immich-CLI, die keine Node.js-Installation voraussetzt. Das Tool eignet sich besonders für den Import von Google-Photos-Takeout-Archiven und versucht dabei, Metadaten wie Alben und Zeitstempel korrekt zu übernehmen.
JPEG-Komprimierung mit jpegli
Um Speicherplatz zu sparen, lassen sich vorhandene JPEG-Bilder mit jpegli-windows-explorer-extension unter nahezu gleichbleibender Qualität verkleinern. Langfristig wäre JPEG XL das bessere Format, aber bis zur breiten Unterstützung in Browsern und Apps ist jpegli eine pragmatische Lösung.
Sicherheit: Immich mit Authelia absichern
Da Immich standardmäßig über das Internet erreichbar ist, empfehle ich zusätzlich Authelia als Authentifizierungs-Layer davor zu schalten. In Kombination mit Traefik als Reverse Proxy lässt sich das recht einfach umsetzen: Traefik leitet Anfragen an Authelia weiter, das eine zusätzliche Anmeldung (z. B. mit Zwei-Faktor-Authentifizierung) erzwingt, bevor der Zugriff auf Immich freigegeben wird. So erhält man eine zusätzliche Sicherheitsschicht vor der eigentlichen Immich-Authentifizierung.
Fazit
Mit Hetzner lässt sich Immich zu folgenden Kosten selbst betreiben:
| Setup | Speicher | Monatliche Kosten |
|---|---|---|
| Minimal | 1 TB | ~9,15 € |
| Empfohlen | 5 TB | ~21,46 € |
Zum Vergleich: ente.io – eine empfehlenswerte, Ende-zu-Ende-verschlüsselte Foto-App – kostet 10 €/Monat für 1 TB bzw. 20 €/Monat für 2 TB. Immich bietet zwar keine E2E-Verschlüsselung, hat dafür aber andere Eigenschaften. Ich nutze ente.io weiterhin in einer kleinen Variante für den direkten, sicheren Geräte-Sync von Medien.
Im Vergleich zu kommerziellen Cloud-Fotodiensten erhältst du mit Immich + Hetzner für dieses Geld:
- Volle Kontrolle über deine Daten (DSGVO-konform in Deutschland gehostet)
- Keine Vendor-Lock-in – deine Fotos bleiben in Originalqualität erhalten
- KI-Features wie Gesichtserkennung und semantische Suche
- Unbegrenzte Nutzer – die ganze Familie kann Immich nutzen
- Automatische Snapshots als integrierte Backup-Lösung
Der Trick liegt in der Trennung von Compute (günstiger VPS) und Storage (günstige Storage Box). Thumbnails und Datenbank laufen auf schneller SSD, während die großen Mediendateien auf dem kosteneffizienten Netzwerkspeicher liegen. So lässt sich schneller Zugriff mit günstigem Speicherplatz kombinieren.
Immich unterstützen
Bitte überlegt euch, Immich zu unterstützen: buy.immich.app. Als Softwareentwickler weiß ich, was es bedeutet, ein Projekt in diesem Umfang zu entwickeln und zu pflegen. Die Entwickler verdienen für ihren Einsatz auf jeden Fall eure Unterstützung.