Kompaktes NAS mit vier Laufwerksschächten auf einem dunklen Holz-Sideboard, davor ausgedruckte Landschaftsfotos und ein Smartphone

Immich einrichten: So läuft meine Google-Fotos-Alternative auf dem NAS

Bei uns nutzt die ganze Familie Immich. Jeder hat seine eigene Bibliothek, und alles, was vorher in Google Fotos lag, haben wir komplett übernommen. Dazu gibt es gemeinsame Alben, die wir zusammen befüllen. So bleiben die eigenen Fotos privat, und die gemeinsamen landen trotzdem an einer Stelle.

In meinem Beitrag zur Docker-Landschaft habe ich Immich nur kurz vorgestellt. Hier geht es um die Einrichtung, so wie sie bei mir auf dem Ugreen DXP4800 Plus läuft. Wenn du ein anderes NAS oder einen kleinen Linux-Server hast, funktioniert das fast genauso. Die Unterschiede stehen jeweils dabei.

Kurz vorweg: So läuft Immich bei mir, Stand Oktober 2026. Immich entwickelt sich schnell weiter, prüf deshalb vor dem Nachbauen die offizielle Doku. Die Einrichtung erfolgt auf eigene Verantwortung. Lösch deine Fotos bei Google oder auf dem Handy erst, wenn du geprüft hast, dass in Immich alles angekommen ist und eine zweite Sicherung existiert.

Hinweis: Ich zeige hier, wie es bei mir läuft. Nachbau auf eigene Gefahr: Mach vorher ein Backup deiner Daten und Einstellungen. Für Schäden oder Datenverlust übernehme ich keine Haftung.

Was du brauchst

Laut offizieller Doku braucht Immich mindestens 6 GB Arbeitsspeicher und 2 CPU-Kerne, empfohlen sind 8 GB und 4 Kerne. Mit nur 4 GB geht es, dann aber ohne maschinelles Lernen, also ohne Gesichtserkennung und Smart-Suche. Das DXP4800 Plus hat 8 GB, das reicht bei mir.

Außerdem:

  • Docker mit dem Compose-Plugin, bei mir verwaltet über Portainer. Auf der Konsole heißt der Befehl docker compose mit Leerzeichen, das alte docker-compose unterstützt Immich nicht mehr.
  • Eine aktuelle Docker-Version. Kommt beim Start ein Fehler zu start_interval und „Docker Engine v25“, ist Docker zu alt.
  • Ein Speicherort für die Fotos mit genug Platz. Vorschaubilder und umgewandelte Videos brauchen laut Doku zusätzlich 10 bis 20 Prozent.
  • Für die Datenbank einen lokalen Speicher, am besten eine SSD. Eine Netzwerkfreigabe (SMB, NFS) ist dafür ausdrücklich nicht unterstützt.

Schritt 1: Netzwerk für den Proxy anlegen

Ich verwalte meine Container mit Portainer. Der Nginx Proxy Manager läuft bei mir selbst als Container und hängt in einem eigenen Docker-Netzwerk namens proxy_net. Alles, was von außen erreichbar sein soll, kommt zusätzlich in dieses Netzwerk. Dann findet der Proxy die Container über ihren Namen, und ich muss keine IP-Adressen pflegen.

Falls es das Netzwerk bei dir noch nicht gibt, legst du es einmal an, entweder in Portainer unter Networks oder auf der Konsole:

docker network create proxy_net

Der Nginx Proxy Manager muss ebenfalls in diesem Netzwerk hängen.

Schritt 2: Den Stack in Portainer anlegen

In Portainer gehst du auf Stacks, dann „Add stack“. Als Namen nehme ich immich-srv-01. Im Web-Editor kommt diese Compose-Datei hinein. Der Name ist frei wählbar. Die Datei basiert auf der offiziellen docker-compose.yml von Immich (Lizenz AGPL-3.0), ich habe sie für Portainer und mein Proxy-Netzwerk angepasst:

services:

  immich-server:
    container_name: immich_server_01
    image: ghcr.io/immich-app/immich-server:release
    # Nur bei Intel-CPU mit Grafikeinheit, siehe „Hardware-Beschleunigung“
    # devices:
    #   - /dev/dri:/dev/dri
    volumes:
      # Fotos, Videos und Immich-Daten
      - ${UPLOAD_LOCATION}:/data
      - /etc/localtime:/etc/localtime:ro
    env_file:
      - stack.env
    ports:
      - "2283:2283"
    depends_on:
      - redis
      - database
    restart: always
    healthcheck:
      disable: false
    networks:
      - immich_internal
      - proxy_net

  immich-machine-learning:
    container_name: immich_machine_learning
    image: ghcr.io/immich-app/immich-machine-learning:release
    volumes:
      - model-cache:/cache
    env_file:
      - stack.env
    restart: always
    healthcheck:
      disable: false
    networks:
      - immich_internal

  redis:
    container_name: immich_redis
    image: docker.io/valkey/valkey:9
    healthcheck:
      test: redis-cli ping | grep -q PONG || exit 1
    restart: always
    networks:
      - immich_internal

  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"
      # Liegt die Datenbank auf einer Festplatte statt einer SSD:
      # DB_STORAGE_TYPE: "HDD"
    volumes:
      - ${DB_DATA_LOCATION}:/var/lib/postgresql/data
    shm_size: 128mb
    restart: always
    healthcheck:
      disable: false
    networks:
      - immich_internal

volumes:
  model-cache:

networks:
  # Das vorhandene Netzwerk des Nginx Proxy Managers
  proxy_net:
    external: true
  # Internes Netzwerk nur für Immich
  immich_internal:
    driver: bridge

Was gegenüber der offiziellen Datei anders ist:

  • Zwei Netzwerke: Datenbank, Valkey und Machine Learning hängen nur im internen Netz immich_internal. Nur der Immich-Server ist zusätzlich im proxy_net, damit der Nginx Proxy Manager ihn erreicht.
  • stack.env statt .env: Portainer schreibt die Umgebungsvariablen, die du unten im Stack-Formular einträgst, in eine Datei mit diesem Namen. Deshalb steht sie unter env_file.
  • Feste Containernamen, damit ich sie im Proxy und im Backup Manager wiederfinde.
  • release statt Versionsvariable: Damit zieht ein Update immer die aktuelle stabile Version. Das heißt aber auch: Kommt eine neue Hauptversion, landet sie beim nächsten Update automatisch bei dir. Die offizielle Vorlage setzt deshalb IMMICH_VERSION=v3 in der .env und bleibt so bei Version 3. Wer es ruhiger mag, nimmt diesen Weg.
  • /dev/dri reicht die Grafikeinheit des Prozessors in den Container. Bei mir steht die Zeile drin, im Codefenster ist sie auskommentiert. Gibt es auf dem Gerät keine Intel-Grafik, würde der Container sonst nicht starten.

In der offiziellen Datei hängt hinter den Images von Valkey und Postgres noch ein langer Code (@sha256:…). Er legt die Version genau fest. Am besten übernimmst du diese beiden Zeilen aus der aktuellen docker-compose.yml von Immich, dann passt die Datenbank immer zur Immich-Version.

Schritt 3: Die Umgebungsvariablen

Unter dem Editor gibt es in Portainer den Bereich „Environment variables“. Dort trage ich diese Werte ein, einzeln oder über „Load variables from .env file“:

# Hier landen die Fotos und Videos
UPLOAD_LOCATION=/pfad/zu/immich/library

# Hier liegt die Datenbank: lokal, keine Netzwerkfreigabe
DB_DATA_LOCATION=/pfad/zu/immich/postgres

TZ=Europe/Berlin

# Nur Buchstaben und Zahlen, keine Sonderzeichen
DB_PASSWORD=HIER-EIN-LANGES-PASSWORT
DB_USERNAME=postgres
DB_DATABASE_NAME=immich

Zwei Dinge, über die man leicht stolpert:

  • Beim Datenbank-Passwort nur A-Z, a-z und 0-9 verwenden. Sonderzeichen machen laut Doku Probleme.
  • TZ sorgt dafür, dass Zeitstempel und geplante Aufgaben in deutscher Zeit laufen.

Die Datenbank gehört am besten auf eine SSD, die Fotos dürfen auf normale Festplatten. Liegt die Datenbank doch auf Festplatten, nimmst du in der Compose die Raute vor DB_STORAGE_TYPE: "HDD" weg.

Bei mir liegt die Datenbank auf den NVMe-SSDs des NAS, die Fotos liegen auf dem RAID 5.

Wer ohne Portainer arbeitet, legt die Compose-Datei als docker-compose.yml ab, schreibt die Variablen in eine Datei .env daneben, ändert stack.env in .env und startet mit dem folgenden Befehl. Das Netzwerk proxy_net aus Schritt 1 muss dann schon existieren, sonst bricht der Start ab:

docker compose up -d

Schritt 4: Starten und ersten Benutzer anlegen

In Portainer auf „Deploy the stack“ klicken. Beim ersten Start lädt Docker vier Images: Immich-Server, Machine Learning, Postgres und Valkey. Danach ist Immich im Heimnetz unter Port 2283 erreichbar:

http://IP-DEINES-NAS:2283

Der erste Benutzer, den du dort anlegst, wird automatisch Administrator. Port 2283 ist nur fürs Heimnetz gedacht. Im Router gibst du ihn nicht frei, von außen geht es nur über den Proxy (Schritt 6).

Optional: Hardware-Beschleunigung

Ich nutze sie derzeit nicht. Wer Videos schneller umwandeln will und eine Intel-CPU ab der 9. Generation hat, kann Quick Sync einschalten. Die offizielle Vorlage holt sich die Einstellungen dafür aus der Datei hwaccel.transcoding.yml. Das Ugreen DXP4800 Plus hat mit dem Pentium Gold eine passende Intel-Grafik. In meiner Compose oben reicht es, die Rauten vor devices und /dev/dri zu entfernen. Danach in Immich unter Administration, Einstellungen, Video-Transkodierung die Hardware-Beschleunigung auf Quick Sync (QSV) stellen.

Schritt 5: Die Handy-App

Für jedes Familienmitglied lege ich unter Administration, Benutzer ein eigenes Konto an. Jeder sieht dann nur seine eigenen Fotos. Die App läuft bei uns auf den Handys und auf dem iPad. Am PC und am Mac nutzen wir Immich im Browser.

Gemeinsame Alben legt einer von uns an und teilt sie mit den anderen. Wer dabei das Recht zum Hinzufügen bekommt, kann eigene Bilder in das Album legen. Die Fotos bleiben dabei in der Bibliothek dessen, der sie hochgeladen hat.

In der App stellst du unter Sicherung ein, welche Alben auf dem Handy hochgeladen werden und ob das nur im WLAN passieren soll.

Optional: Umzug von Google Fotos

Der Weg führt über Google Takeout. Dort lässt sich unter takeout.google.com alles exportieren, was bei Google liegt. Dort wählst du nur „Google Fotos“ aus und lässt dir ZIP-Archive erstellen. Je nach Größe der Sammlung dauert das ein paar Stunden bis Tage, dann kommt eine Mail mit den Download-Links.

Beim Hochladen gibt es einen Haken: Google packt Aufnahmedatum, Ort und Beschreibung nicht in die Bilder selbst, sondern in eigene JSON-Dateien daneben. Wer die Bilder einfach so hochlädt, hat danach falsche Daten in der Zeitachse.

Genau dafür gibt es das kostenlose Werkzeug immich-go. Es stammt nicht vom Immich-Team, sondern von einem anderen Entwickler, und gilt laut eigener Beschreibung noch als frühe Version. Probier es deshalb erst mit einem kleinen Archiv aus. Es liest die Takeout-Archive direkt, ordnet die JSON-Dateien den richtigen Bildern zu, übernimmt die Alben und überspringt Bilder, die schon in Immich liegen. Dafür braucht es einen API-Schlüssel, den jeder Benutzer in Immich in seinen Kontoeinstellungen unter „API-Schlüssel“ anlegt. Welche Berechtigungen der Schlüssel braucht, steht in der Anleitung von immich-go. Nach dem Import kannst du ihn wieder löschen. Weil jeder bei uns eine eigene Bibliothek hat, läuft der Import mit dem Schlüssel der jeweiligen Person:

immich-go upload from-google-photos --server=http://IP-DEINES-NAS:2283 --api-key=DEIN-API-SCHLUESSEL /pfad/zu/takeout-*.zip

Die ZIP-Dateien müssen dafür nicht entpackt werden. So haben wir unsere komplette Google-Fotos-Sammlung übernommen, für jede Person mit ihrem eigenen Schlüssel.

Schritt 6: Von unterwegs über den Nginx Proxy Manager

Schaubild: Fotos gehen von Handy und iPad über den Nginx Proxy Manager zum Immich-Stack auf dem NAS und werden wöchentlich aufs TrueNAS gesichert

Wie ich den Nginx Proxy Manager grundsätzlich nutze, steht in einem eigenen Beitrag. Für Immich lege ich einen Proxy Host an:

  • Domain: eine eigene Subdomain, z. B. fotos.example.com. Immich läuft nur direkt auf einer (Sub-)Domain, nicht unter einem Unterpfad wie example.com/fotos.
  • Ziel: http, Hostname immich_server_01, Port 2283. Das klappt, weil beide im proxy_net hängen. Ohne gemeinsames Netzwerk nimmst du die IP des NAS.
  • Websockets Support: an
  • SSL: Let’s-Encrypt-Zertifikat, „Force SSL“ an

Unter „Advanced“ kommen die Werte, die Immich für Nginx empfiehlt. Sonst brechen große Videos beim Hochladen ab:

client_max_body_size 50000M;
proxy_request_buffering off;
client_body_buffer_size 1024k;
proxy_read_timeout 600s;
proxy_send_timeout 600s;
send_timeout 600s;

Danach in Immich unter Administration, Einstellungen, Servereinstellungen die externe Domain eintragen. Dann zeigen geteilte Links auf die richtige Adresse.

Weil die Fotos jetzt aus dem Internet erreichbar sind: Jedes Konto bekommt ein eigenes, langes Passwort, und geteilte Links bekommen am besten ein Ablaufdatum oder werden gelöscht, wenn sie nicht mehr gebraucht werden.

Schritt 7: Sicherung

Immich legt jede Nacht um 2 Uhr selbst eine Sicherung der Datenbank an und behält die letzten 14. Die liegen unter UPLOAD_LOCATION/backups. Darin stecken aber nur die Metadaten, also Alben, Gesichter, Benutzer. Die Fotos selbst müssen extra gesichert werden.

Wichtig sind diese Ordner unter UPLOAD_LOCATION:

library/   Originale (wenn die Speichervorlage aktiv ist)
upload/    Originale
profile/   Profilbilder
backups/   Datenbank-Sicherungen

thumbs/ und encoded-video/ kann Immich nach einer Wiederherstellung neu erzeugen. Die kannst du weglassen, das spart Platz.

Bei mir übernimmt das mein Docker Backup Manager: Er sichert die Immich-Container einmal pro Woche per SMB aufs TrueNAS.

Updates

Vor jedem Update lohnt ein Blick in die Release Notes auf GitHub. Immich ändert öfter etwas, das man von Hand nachziehen muss, zum Beispiel das Postgres-Image in der Compose-Datei.

In Portainer öffnest du den Stack, klickst auf „Update the stack“ und schaltest dabei „Re-pull image and redeploy“ ein. Weil in der Compose release steht, holt Docker dann die neueste stabile Version. Auf der Konsole geht dasselbe mit:

docker compose pull
docker compose up -d

Mein Fazit

Für uns hat sich der Umzug gelohnt. Unsere Fotos liegen zu Hause statt bei Google, und die gemeinsamen Alben funktionieren für die ganze Familie. Ich würde alles genauso wieder aufbauen.

Wer auch Dateien und Scans selbst hosten will: So läuft bei mir Nextcloud All-in-One.

Titelbild KI-generiert.

Schreibe einen Kommentar

Kommentarregeln: Bleib sachlich und freundlich. Keine Beleidigungen, keine Werbung, keine Links zu fremden Shops, keine persönlichen Daten anderer und nichts Rechtswidriges. Ich behalte mir vor, Kommentare nicht freizuschalten, zu kürzen oder zu löschen. Rechtswidrige Inhalte kannst du mir über das Kontaktformular melden (bitte Link zum Kommentar und kurze Begründung). Ich prüfe Meldungen zeitnah.

Deine E-Mail-Adresse wird nicht veröffentlicht. Pflichtfelder sind mit * markiert.

Mit dem Absenden werden Name, E-Mail-Adresse, Kommentar und IP-Adresse gespeichert. Name und Kommentar sind öffentlich sichtbar. Mehr dazu in der Datenschutzerklärung. Der erste Kommentar wird vor der Veröffentlichung von mir geprüft.

Nach oben scrollen