Es gibt genug Anleitungen, wie man n8n mit Docker in zehn Minuten zum Laufen bringt. Die funktionieren auch. Das Problem beginnt danach: Wenn der Container das erste Mal neu startet und die Workflows weg sind. Wenn der Zeitplan um 6 Uhr feuert, obwohl 7 Uhr eingestellt ist. Wenn nach einem Update plötzlich die Datenbank nicht mehr passt. Dieser Beitrag ist das Setup, das bei uns im Betrieb seit Monaten läuft – mit allem, was ich beim ersten Mal falsch gemacht habe.

Ob du überhaupt selbst hosten solltest, habe ich hier ehrlich verglichen: n8n selbst hosten vs. n8n Cloud. Wenn die Antwort „selbst“ ist, geht es hier weiter.

Die kurze Antwort (TL;DR)

  • Docker Compose, nicht docker run. Eine Datei, die alles beschreibt – Container, Datenbank, Volumes, Zeitzone. Die Datei ist deine Dokumentation.
  • Postgres statt SQLite, sobald mehr als drei Workflows laufen. SQLite ist der Grund für die meisten „Daten weg“-Geschichten.
  • Zeitzone dreimal setzen: im n8n-Container (GENERIC_TIMEZONE und TZ), in der Datenbank und im Host. Sonst laufen Zeitpläne falsch.
  • Backup vor dem ersten produktiven Workflow, nicht nach dem ersten Crash. Ein nächtlicher pg_dump reicht.
  • Updates bewusst, nicht per latest-Tag. Versionsnummer pinnen, Changelog lesen, Backup, dann Update.

Warum „läuft erstmal“ nicht reicht

Mein erster n8n-Server war ein docker run-Einzeiler aus einem Tutorial. Er lief, ich baute das Formular für die Azubi-Zeiterfassung, dann den zweiten Workflow, dann den dritten. Und dann hat mich ein Neustart des Rechners alles gekostet: Der Container kam zurück, die Workflows nicht. SQLite-Datei im Container, kein Volume, kein Backup. Zwei Wochen Arbeit neu gebaut – die Geschichte steht hier.

Seitdem gilt für mich: Ein Automatisierungsserver im Betrieb ist Infrastruktur, keine Bastelei. Er muss einen Neustart, ein Update und einen Stromausfall überleben, ohne dass ich etwas davon merke. Das folgende Setup tut das.

Das Setup: Docker Compose mit Postgres

Ein Verzeichnis, drei Dateien: docker-compose.yml, .env für die Geheimnisse und ein Ordner backups/. So sieht die Compose-Datei bei mir im Kern aus (gekürzt, aber lauffähig):

services:
  postgres:
    image: postgres:16
    restart: unless-stopped
    environment:
      POSTGRES_USER: n8n
      POSTGRES_PASSWORD: ${DB_PASSWORD}
      POSTGRES_DB: n8n
      TZ: Europe/Berlin
    volumes:
      - ./data/postgres:/var/lib/postgresql/data
    healthcheck:
      test: ["CMD-SHELL", "pg_isready -U n8n"]
      interval: 10s
      retries: 5

  n8n:
    image: n8nio/n8n:1.100.1   # Version pinnen, nicht 'latest'
    restart: unless-stopped
    depends_on:
      postgres:
        condition: service_healthy
    ports:
      - "127.0.0.1:5678:5678"   # nur lokal, davor kommt der Reverse Proxy
    environment:
      DB_TYPE: postgresdb
      DB_POSTGRESDB_HOST: postgres
      DB_POSTGRESDB_DATABASE: n8n
      DB_POSTGRESDB_USER: n8n
      DB_POSTGRESDB_PASSWORD: ${DB_PASSWORD}
      N8N_ENCRYPTION_KEY: ${N8N_ENCRYPTION_KEY}
      GENERIC_TIMEZONE: Europe/Berlin
      TZ: Europe/Berlin
      N8N_HOST: n8n.deine-domain.de
      WEBHOOK_URL: https://n8n.deine-domain.de/
      N8N_PROTOCOL: https
    volumes:
      - ./data/n8n:/home/node/.n8n

Drei Dinge daran sind nicht verhandelbar:

  1. Der N8N_ENCRYPTION_KEY. Damit verschlüsselt n8n deine Zugangsdaten (Mail, ERP, APIs). Geht der Schlüssel verloren, sind alle Credentials unbrauchbar – auch mit Datenbank-Backup. Der Schlüssel gehört in die .env und zusätzlich an einen zweiten Ort (Passwortmanager).
  2. Volumes auf dem Host. ./data/postgres und ./data/n8n liegen außerhalb des Containers. Ein docker compose down löscht nichts mehr.
  3. Version pinnen. latest heißt: Irgendwann morgens läuft eine andere Version als gestern Abend, und du weißt nicht, warum der Workflow hakt.

Stolperstein 1: Die Zeitzone

Das war meine hartnäckigste Fehlersuche. Der Wochenreport für die Azubis sollte freitags um 15 Uhr rausgehen – und kam um 13 Uhr. Im Sommer. Im Winter um 14 Uhr. Der Container lief auf UTC, n8n zeigte die Zeit in der Oberfläche in meiner Zeitzone an, aber der Cron-Trigger rechnete in der Container-Zeit.

Die Lösung ist unspektakulär, aber sie muss vollständig sein: GENERIC_TIMEZONE und TZ im n8n-Container, TZ in der Datenbank, und der Host selbst auf Europe/Berlin. Nach jeder Änderung: Container neu starten und einen Testworkflow mit „aktuelle Zeit“ laufen lassen. Nicht raten.

Stolperstein 2: Backup

Mein Backup ist ein Cron-Job auf dem Host, jede Nacht um 2 Uhr:

#!/bin/bash
cd /opt/n8n
docker compose exec -T postgres pg_dump -U n8n n8n | gzip > backups/n8n-$(date +%F).sql.gz
cp .env backups/env-$(date +%F).bak
find backups/ -mtime +30 -delete

Dazu kopiert ein zweiter Job den Ordner backups/ auf unser NAS. Wichtig: Die .env mit dem Encryption Key gehört mit ins Backup – ein Datenbank-Dump ohne Schlüssel ist ein Haufen verschlüsselter Credentials.

Und: Einmal zurückspielen üben. Auf einem zweiten Rechner, mit einem alten Dump. Wer das nie gemacht hat, hat kein Backup, sondern eine Hoffnung.

Stolperstein 3: Updates

n8n veröffentlicht oft. Ich update etwa monatlich, und zwar so: Changelog lesen (Breaking Changes stehen oben), Backup laufen lassen, Versionsnummer in der Compose-Datei ändern, docker compose pull && docker compose up -d. Danach die drei wichtigsten Workflows manuell anstoßen. Dauert eine Viertelstunde, und ich weiß hinterher, dass es läuft – statt es am Montagmorgen von der Verwaltung zu erfahren.

Was ich nicht mehr mache: Major-Versionen am Freitagnachmittag. Und Updates ohne vorher zu prüfen, ob die Postgres-Version noch passt.

Stolperstein 4: Von außen erreichbar, aber nicht offen

n8n braucht eine öffentliche Adresse, wenn Webhooks von außen kommen sollen (Formulare, Mail-Dienste). Bei mir läuft davor ein Reverse Proxy (Caddy) mit automatischem Zertifikat, und n8n selbst hört nur auf 127.0.0.1. Dazu ein Login mit langem Passwort und – wichtig für die Betriebsdaten – der Zugriff auf das ERP läuft nur intern im Netz, nie über das Internet. Für den Fernzugriff auf die Oberfläche nutze ich ein VPN (Tailscale), nicht eine offene Portfreigabe.

Was das im Alltag bedeutet

Seit dem Umbau auf dieses Setup: kein Datenverlust mehr, zwei Rechner-Neustarts ohne Nacharbeit, ein Stromausfall, nach dem alles von allein wieder hochkam. Die Workflows laufen – Azubi-Wochenreport, Revisionsunterlagen, Ausschreibungs-Radar, die nächtlichen Snapshots fürs Cockpit. Und wenn ich einen neuen Workflow baue, denke ich nicht mehr darüber nach, ob der Server ihn morgen noch kennt.

Der Aufwand für das Setup: ein Abend. Der Aufwand, ihn nicht zu machen: bei mir zwei Wochen.

Weiterlesen auf handwerkflow:
n8n selbst hosten vs. Cloud – der Vergleich
Azubi-Zeiterfassung automatisieren – mein erster Workflow
Alle Projekte aus dem Betrieb

Häufige Fragen (FAQ)

Reicht SQLite nicht für einen kleinen Betrieb?

Zum Ausprobieren ja. Sobald Workflows wichtig werden, nein: Postgres ist robuster bei parallelen Ausführungen, lässt sich sauber sichern und macht Updates unproblematischer.

Welche Hardware braucht n8n?

Wenig. Bei uns läuft es auf einem kleinen Server mit 2 CPU-Kernen und 4 GB RAM neben Postgres und Grafana. Ein Mini-PC oder ein kleiner VPS reicht.

Was passiert, wenn ich den Encryption Key verliere?

Die Workflows bleiben, aber alle gespeicherten Zugangsdaten sind unbrauchbar und müssen neu eingegeben werden. Deshalb: Schlüssel an zwei Orten sichern.

Muss n8n öffentlich erreichbar sein?

Nur, wenn externe Dienste Webhooks schicken sollen. Für rein interne Automatisierungen (ERP, Mail, Dateien) reicht das lokale Netz plus VPN.


Schreibe einen Kommentar

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