Was Docker ist: das minimal notwendige Wissen für n8n-Einsteiger

Der Punkt, an dem die Installation von n8n am häufigsten hängen bleibt, ist nicht n8n selbst, sondern das Docker davor. Man kopiert fünf Befehlszeilen aus dem Tutorial, der container startet, im Interface zwei Klicks und es läuft – und am nächsten Tag stellt man fest, dass alle Workflows weg sind. Der Grund: In diesen fünf Zeilen fehlt eine -v。

Dieser Artikel behandelt nur den Teil von Docker, den man für die Installation von n8n braucht: image, container, volume, port. Vier Begriffe. Netzwerkmodi, Compose und das eigene Bauen von images kommen erst dran, wenn man sie wirklich braucht – was man vorher lernt, vergisst man sowieso.

Voraussetzung ist nur eines: im Terminal Befehle eingeben können und wissen, was ein „port" ist. Keine bisherige Berührung mit Docker schadet überhaupt nicht.

Warum n8n am Ende immer in Docker landet

Die offizielle Installationsseite nennt mehrere Wege: globale Installation per npm, direktes Ausführen per npx, Docker, Desktop-Version. Die ersten beiden sind am leichtesten, eine npm install -g n8n und fertig. Das Problem: Sie binden n8n fest an das Node auf deiner Maschine. n8n ist bei der Node-Version wählerisch; die Dokumentation nennt den Bereich 20.19 bis 24.x. Wenn du irgendwann für ein anderes Projekt Node auf 26 anhebst, streikt n8n mit – und die Fehlermeldung ist nicht unbedingt menschenlesbar.

Docker geht anders vor: n8n wird zusammen mit dem benötigten Node, den Systembibliotheken und den Zeitzonendaten in ein Paket gepackt, das auf jedem Rechner gleich läuft. Ich habe extra einen Blick in das image 2.43.7 geworfen: Node ist 26.7.0, das Basis-image ist Alpine. Das hat überhaupt nichts damit zu tun, ob auf deinem Host Node 18 oder 26 installiert ist.

Die Kosten muss man auch klar benennen. Du hast eine zusätzliche Schicht, um die du dich kümmern musst: Das Image belegt Speicherplatz (2.43.7 entpackt 1.8 GB), bei Problemen musst du an einer weiteren Stelle Logs prüfen, und das Upgrade geht von „npm update" zu „Image austauschen und neu starten" über. Ich finde es lohnenswert – beim Upgrade Tag ändern, Container löschen, neu starten, drei Minuten, ohne sich um die Node-Version kümmern zu müssen.

Wenn du nur zwei Tage lokal herumspielst, würde ich nicht zu Docker raten, npm ist schneller. Wenn du es langfristig betreiben oder Kollegen zur Verfügung stellen willst, nimm direkt Docker und mach keine Umwege.

Vier Begriffe: Image, Container, Volume, Port

Image

Ein Image ist ein vorgefertigtes, schreibgeschütztes Paket, das ein vollständiges Dateisystem enthält, mit dem n8n laufen kann.n8nio/n8n ist der Name,2.43.7 ist das Tag. Unter einem Namen hängen viele Tags, ein Tag entspricht einer Version.

Tag schreiben latestbedeutet „neueste stabile Version". In der Produktion würde ich das nicht so schreiben: Wenn der Container irgendwann neu startet und dabei ein neues Image zieht, ändert sich das Verhalten, und du weißt nicht einmal, wo du suchen sollst. Versionsnummer fest schreiben, das Upgrade als eigene Aufgabe behandeln.

Docker Hub 上 n8nio/n8n 的 2.43.7 标签页,显示 docker pull 命令与压缩体积
Die Tag-Seite von Docker Hub, eine Version pro Zeile. Die amd64-Version von 2.43.7 ist komprimiert 260.51 MB, arm64 ist 259.76 MB. Der Eintrag rechts docker pull ist genau der, den du eingeben musst

Container

Das Image ist statisch.docker run Der Prozess, der danach läuft, heißt Container. Der Container entspricht dem Image plus einer beschreibbaren Schicht, alles, was du darin änderst, wird auf dieser Schicht geschrieben. Wird der Container gelöscht, verschwindet diese Schicht mit – dieser Satz ist die Quelle aller späteren Fallstricke.

卷

Deshalb dürfen die Daten von n8n nicht im Container liegen. Ein Volume ist ein Verzeichnis auf dem Host, das von Docker verwaltet und in einen bestimmten Pfad im Container gemountet wird. Der Pfad, den n8n erkennt, ist /home/node/.n8n, die Datenbank, die Verschlüsselungsschlüssel und die Ereignisprotokolle sind alle dort.

Ich habe nachgezählt: ein gerade erst erstelltes owner-Konto, das einmal einen Workflow ausgeführt hat .n8n Verzeichnis, 5,5 MB. Davon database.sqlite 1,5 MB, zusätzlich gibt es eine 4 MB große -wal Datei. So wenig Zeug, und wenn es verloren geht, muss alles neu gemacht werden.

port

-p 5678:5678, links vom Doppelpunkt ist der Host-port, rechts der port im container. Das n8n im container lauscht immer auf 5678 (außer du änderst N8N_PORT), wenn du außen eine andere Nummer willst, änderst du nur die linke Seite:-p 8080:5678。

geschrieben als 127.0.0.1:5678:5678 bindet nur an den lokalen Rechner, von außen kommt man nicht rein. Beim Testen verwende ich immer diese Schreibweise, damit ich nicht vergesse, es zu schließen.

Zuerst Docker installieren

Auf Ubuntu / Debian ist das offizielle Skript am einfachsten:

curl -fsSL https://get.docker.com | sh

Es fügt die offizielle Quelle hinzu, installiert docker-ce, bringt das compose-Plugin mit. Wer Bedenken hat, „was aus curl kommt, direkt an sh zu verfüttern“, geht brav den Weg über die offizielle apt-Quelle, die Schritte stehen in der Docker-Dokumentation, ist halt etwas länger.

Nach der Installation zwei Befehle eingeben, um die Version zu prüfen:

docker --version
# Docker version 29.1.3, build 29.1.3-0ubuntu3~24.04.2

Meine 232 hier ist Ubuntu 24.04 + Docker 29.1.3. Du kannst 24 oder 25 nehmen, die Befehle sind identisch.

Docker 默认要 root 或者 sudo。有人说把用户加进 docker 组就不用 sudo 了,这话对,但等于给了那个用户 root 权限,理由在安全那节。

起一个 n8n,三步

第一步:建卷

docker volume create n8n_data
# n8n_data

回显卷名就是建好了。这步不建也行,docker run 里写 -v n8n_data:/home/node/.n8n 会自动创建——不过先建一次,你能确认它真在。

第二步:跑起来

docker run -d 
  --name n8n 
  -p 127.0.0.1:5678:5678 
  -e TZ=Asia/Shanghai 
  -e GENERIC_TIMEZONE=Asia/Shanghai 
  -e N8N_ENFORCE_SETTINGS_FILE_PERMISSIONS=true 
  -v n8n_data:/home/node/.n8n 
  n8nio/n8n:2.43.7

跟官方文档的原始命令比,我改了两处。

一处是加了 -d。文档给的是 docker run -it --rm,前台跑,终端一关或者 Ctrl+C,n8n 就停;--rm 还顺手把容器删了。调试时这么用很清爽,长期跑不行,加 -d 让它后台待着。

另一处是端口前面补了 127.0.0.1:Im Dokument steht -p 5678:5678, das entspricht einer Bindung an 0.0.0.0; sobald die Maschine eine öffentliche IP hat, kann jeder, der 5678 scannt, deine Login-Seite sehen. Bei meiner 232 ist 5678 belegt, tatsächlich verwendet wird -p 127.0.0.1:5681:5678, die Zuordnung ist dieselbe.

Beide Zeitzone-Variablen müssen gesetzt werden.TZ steuert die Systemzeit des Containers,GENERIC_TIMEZONE steuert, wie n8n selbst die Zeit berechnet; der Schedule Trigger richtet sich nach letzterer. Wird nur TZgesetzt, laufen die zeitgesteuerten Aufgaben weiterhin nach UTC, und dein vermeintliches 9 Uhr morgens wird zu 17 Uhr Pekinger Zeit. In den Logs bleibt dabei keine einzige Anomalie zurück.

Dritter Schritt: Logs ansehen und warten, bis es hochkommt

docker logs -f n8n

Beim ersten Start laufen Dutzende Datenbankmigrationen durch,Starting migration ... 和 Finished migration ... wechseln sich ab, das ist normal. Warte, bis diese beiden Zeilen erscheinen:

Version: 2.43.7

Editor is now accessible via:
http://localhost:5678

Die http://localhost:5678 ist eine containerinterne Adresse, die sich im Browser nicht öffnen lässt. Was du öffnen kannst, ist http://服务器IP:5678, oder auf dem lokalen Rechner http://127.0.0.1:5678. Diese Zeile hat schon viele getäuscht, mich beim ersten Lauf eingeschlossen.

2.43.7 gibt beim Start außerdem fünf deprecation-Warnungen aus, die N8N_RUNNERS_MODE、N8N_UNVERIFIED_PACKAGES_ENABLED Diese Defaults müssen später geändert werden. Sie beeinträchtigen die Nutzung nicht, sondern bereiten den Weg für zukünftige Versionen. Außerdem gibt es noch eine Zeile Failed to start Python task runner in internal mode. because Python 3 is missing from this system.— im Image ist kein Python installiert, wenn du nur den JS-Code-Node verwendest, musst du dich überhaupt nicht darum kümmern.

新容器里的 n8n 首次打开是 Set up owner account 页面
Wenn ein neuer container zum ersten Mal geöffnet wird, erscheint genau dieses „Set up owner account". Null Workflows, alles muss von hier aus beginnen

Nach dem Erstellen des Kontos geht es hinein. Dieser Schritt ist sinnlos, wenn er nicht ins Volume geschrieben wird — unten wird bei der Verifizierung erklärt, wie man bestätigt, dass es tatsächlich auf die Festplatte geschrieben wurde.

Wie man feststellt, dass die Installation erfolgreich war

Vier Prüfungen, alle im Terminal durchzuführen.

  1. docker ps Darin ist STATUS Up, PORTS hat ein Mapping, IMAGE ist der von dir angegebene tag.
  2. curl -s http://127.0.0.1:5678/healthz Gibt zurück {"status":"ok"}. Diese Schnittstelle zeigt nur, dass der Prozess läuft.
  3. docker exec n8n n8n --version 回 2.43.7, stimmt mit dem von dir angegebenen tag überein.
  4. docker restart n8n, warte ein Dutzend Sekunden und öffne dann die Seite erneut, es sollte nicht mehr verlangen, ein Konto zu erstellen.

Punkt 4 wird am leichtesten übersehen und ist am wertvollsten. Er verifiziert zwei Dinge gleichzeitig: Das Volume ist korrekt gemountet, und die Daten liegen tatsächlich außerhalb des containers.

容器里的 n8n 运行一个手动触发加编辑字段的工作流,输出三个字段
Erstelle einen Workflow im container und führe ihn einmal aus, der Node „drei Felder schreiben" gibt 1 item und drei Spalten aus. Wenn diese Oberfläche herauskommt, bedeutet das, dass es nicht nur eine Webseite ist, die sich öffnen lässt

Als ich diesen Screenshot gemacht habe, habe ich nebenbei einen Blick in den container geworfen .n8n, 5.5 MB, das passt zu dem, was oben gesagt wurde. Wenn bei dir du -sh nur ein paar hundert K herauskommen, sind die Daten wahrscheinlich in die beschreibbare Schicht des Containers geschrieben worden, das Volume wurde nicht gemountet.

In welcher Datei die Daten tatsächlich liegen

Nachdem das Volume erstellt wurde, bestimmt Docker den tatsächlichen Speicherort auf dem Host, das prüfst du mit diesem Befehl:

docker volume inspect n8n_data
# [
#     {
#         "CreatedAt": "2026-11-02T09:28:41+08:00",
#         "Driver": "local",
#         "Mountpoint": "/var/lib/docker/volumes/n8n_data/_data",
#         "Name": "n8n_data",
#         "Scope": "local"
#     }
# ]

„Mountpoint" ist der tatsächliche Speicherort auf dem Host. Bei dieser Maschine habe ich das Docker-Datenstammverzeichnis verschoben nach /data/docker, deshalb sehe ich /data/docker/volumes/n8n_data/_data; auf einer Maschine mit Standardinstallation ist es das oben genannte /var/lib/docker/.... Maßgeblich ist die Ausgabe deiner eigenen Maschine.

Im Container sieht es so aus, wie n8n es sieht:

docker exec n8n ls -la /home/node/.n8n
# -rw-r--r-- 1 node node 1519616 Nov  2 09:29 database.sqlite
# -rw-r--r-- 1 node node   32768 Nov  2 09:38 database.sqlite-shm
# -rw-r--r-- 1 node node 4136512 Nov  2 09:37 database.sqlite-wal
# -rw-r--r-- 1 node node    7972 Nov  2 09:37 n8nEventLog-1.log
# -rw-r--r-- 1 node node     526 Nov  2 09:38 n8nEventLog.log

Workflows, Ausführungsprotokolle, verschlüsselte Credentials, alles liegt in database.sqlite . Der zum Entschlüsseln der Credentials benötigte Schlüssel liegt im selben Verzeichnis, standardmäßig in der Datei config , die beim ersten Start automatisch generiert wird.

Ein n8n-Backup besteht also aus zwei Dingen: diesem Verzeichnis und der Versionsnummer. Wenn du nur die sqlite sicherst und nicht den Schlüssel, sind die Credentials nach der Wiederherstellung auf einer anderen Maschine alle unlesbar.

Wenn du stattdessen ein eigenes Host-Verzeichnis verwenden möchtest (zum Beispiel /data/n8n), dann -v n8n_data:/home/node/.n8n Ersetze es durch -v /data/n8n:/home/node/.n8n Das ist ein „Bind-Mount“: Das Verzeichnis verwaltest du selbst, Backups sind intuitiver, der Preis dafür ist, dass du die Berechtigungen selbst in Ordnung bringen musst — und genau das ist die nächste Falle.

Sechs Fehler, die dir wirklich begegnen werden

1. -v vergessen: Container löschen heißt Datenbank löschen

Ich habe zwei Container als Vergleich genommen, dieselbe Maschine, dasselbe Image: Der mit -v n8n_data:/home/node/.n8n gibt nach dem Neustart über die Schnittstelle für „ob die Ersteinrichtung angezeigt werden soll“ zurück: false; der andere ohne -v gibt über dieselbe Schnittstelle zurück: true— er ist wieder zu einer leeren Instanz geworden.

Der ganze Vorgang meldet keinen Fehler, löst keine Warnung aus. Du öffnest irgendwann eines Tages und stellst fest, dass die Workflows weg sind.

So erkennst du es:docker inspect n8n, scrolle nach oben und suche den Abschnitt "Mounts" , wenn dort "Destination": "/home/node/.n8n" auftaucht, ist es gemountet; ist der ganze Abschnitt leer, dann ist es gefährlich.

2. Host-Verzeichnis mounten, EACCES wird gemeldet

Wenn man ein bind mount verwenden will, das Verzeichnis ist bereits erstellt und wird direkt gemountet, also:

Error: Failed to load command "start"
Error: EACCES: permission denied, open '/home/node/.n8n/config'

Zuvor wurden noch normal die Migrationslogs ausgegeben, plötzlich blieb es hier hängen. Weil n8n im image nicht root ist, sondern ein Benutzer mit uid 1000 node(docker exec n8n id Man kann sehen uid=1000(node)), und dein mkdir erstellte Verzeichnis hat als Besitzer root, 755, andere können nicht hineinschreiben.

Besitzer ändern reicht:

chown -R 1000:1000 /data/n8n

Nach der Änderung erneut ausführen, dasselbe Verzeichnis, derselbe Befehl, 200, normal gestartet, und die Dateien sind tatsächlich im Host-Verzeichnis gelandet. Es ist egal, wer auf dem Host uid 1000 ist, im container wird 1000 erkannt.

3. Port ist belegt

docker: Error response from daemon: failed to set up container networking:
driver failed programming external connectivity on endpoint n8n
(...): failed to bind host port 0.0.0.0:5678/tcp: address already in use

Das bedeutet, dass Port 5678 auf dem Host bereits von jemandem verwendet wird, das hat mit dem Inneren des containers überhaupt nichts zu tun. Zuerst schauen, wer es ist:

ss -ltnp 'sport = :5678'

Häufig ist es so, dass dein früherer n8n container noch läuft,docker ps Man kann sehen. Oder der alte container wurde gelöscht, aber nicht sauber entfernt, am einfachsten ist es, erst einmal mit einem anderen Port zu starten.

4. Zugriff über IP + http, nach dem Login springt es zurück zur Login-Seite

Die Seite lässt sich öffnen, Benutzername und Passwort sind auch richtig, beim Klick auf Login gibt es keinen Fehler, dann kehrt die Seite zum Login-Feld zurück. Es sieht aus wie ein falsches Passwort, tatsächlich ist es ein cookie-Problem.

Das Login-cookie von n8n trägt Secure Markierung (N8N_SECURE_COOKIE Standardmäßig ist es true), und der Browser erlaubt das Speichern nur unter HTTPS. Wenn du über http zugreifst, liefert der Server trotzdem 200 zurück, aber der Browser verwirft dieses Cookie sofort, sodass der nächste Request wieder keinen Login-Status hat.

Zwei Wege: Der saubere Ansatz ist, davor eine Nginx-Schicht mit Zertifikat zu setzen; für temporäres Debugging im 内网 fügst du -e N8N_SECURE_COOKIE=falsehinzu, und nach dem Debuggen denk daran, diese Zeile zu löschen. Behandle das nicht als Langzeitkonfiguration – das läuft darauf hinaus, dass dein Benutzername und Passwort über eine Klartextstrecke laufen.

5. Terminal schließen, und n8n stoppt mit

Gemäß dem Dokumentationsbefehl docker run -it --rm ausgeführt, beendet Ctrl+C den Prozess. Es ist kein Hintergrunddienst, sondern ein Vordergrundprozess in deinem Terminal.

补 -d Erneut ausführen; bei denen, die bereits laufen,docker start n8n kann es ebenfalls zurückholen, aber dieser container wurde bereits mit --rm Wenn er gelöscht wurde, bleibt nur ein erneutes docker run– die Daten liegen im Volume und sind noch da.

6. latest verwendet, und eines Tages hat sich das Verhalten geändert

Keine Fehlermeldung, keine Warnung, nur dass nach einem Neustart eines Tages die Standardwerte der Nodes, die Oberfläche oder sogar ein Parametername anders sind. Der Grund ist, dass du eine neue Version gezogen hast.

Version fest verdrahten und das Upgrade als eine ernsthafte Angelegenheit behandeln: zuerst das Volume sichern, dann den Tag wechseln, nach dem Start zwei kritische Workflows laufen lassen und die Ergebnisse prüfen. Das Upgrade selbst hat keinen großen technischen Anspruch, die Mühe liegt darin, „nicht zu wissen, was sich geändert hat“.

Ein paar sicherheitsrelevante Punkte im Zusammenhang mit n8n

Stecke 5678 nicht direkt ins öffentliche Netz.n8n hat eine Login-Seite, aber es ist eine selbstgehostete Anwendung, es gibt keinen zusätzlichen Schutz über den Login hinaus, Scanner suchen täglich nach solchen Ports. Auf 0.0.0.0 ohne Reverse-Proxy und ohne HTTPS ist wie den Haustürschlüssel an die Tür zu hängen. Meine Schreibweise beim Testen -p 127.0.0.1:5678:5678 hat das Äußere bereits abgeschirmt.

docker Gruppe entspricht root.Wer / in einen container mounten kann, kann jede Datei auf dem Host ändern. Denk daran, bevor du Kollegen Berechtigungen gibst.

Volumes wie Schlüssel behandeln.Darin ist database.sqlite die verschlüsselte Ablage aller Credentials, im selben Verzeichnis liegt der Entschlüsselungsschlüssel. Wer beides zusammen kopiert, hat alle Tokens deiner Drittanbieter-Konten im Klartext. Wo das Backup liegt, ist wichtiger als das Backup selbst.

Schreib keine Passwörter in die Kommandozeile.docker run -e DB_PASSWORD=xxx bleibt in der Ausgabe von docker inspect stehen, jeder der es ausführt kann es sehen. Für sensible Werte eine env-Datei verwenden, oder _FILE die Variablen mit Suffix.

Kurzfassung

Vier Wörter reichen zum Loslegen: Das image ist das Paket, der container ist das laufende Paket, das volume ist das Stück Land außerhalb des Pakets, der port ist die Hausnummer.

Beim Installieren von n8n gibt es wirklich nur eine Stelle, an der es schiefgehen kann: Das Volume ist nicht gemountet. Es gibt keine Fehlermeldung, und du merkst es nicht sofort – wenn du es merkst, ist der Workflow schon weg. Deshalb ist das Erste nach der Installation docker restart einmal, um zu prüfen, ob die Daten noch da sind.

Der Rest ist eine Frage der Routine. Mit der Zeit wirst du feststellen, dass der größte Vorteil von Docker nicht „plattformübergreifend“ ist, sondern „im Fehlerfall alles löschen und neu anfangen“ – die Daten liegen im Volume, der Container kann ohnehin jederzeit weggeworfen werden.

Der vorherige Beitrag istn8n-Startfehler und Portbelegung prüfen, dort geht es um Fälle, in denen es nicht startet. Das Inhaltsverzeichnis der gesamten Serie isthier, die Fehlerfälle habe ich separat auf derFehlerbehebung-Seite zusammengestellt.

Referenzen

  • Install with Docker: offizielle docker run Befehle,docker volume create、/home/node/.n8n Volume-Erläuterungen sowie die Schritte zum Aktualisieren des Images
  • Install using Docker Compose: die Konfiguration der Compose-Version,5678:5678 Der Kommentar lautet „der einzige Port, der nach außen freigegeben werden sollte“
  • Deployment-Umgebungsvariablen:N8N_PORT Standard 5678,N8N_LISTEN_ADDRESS Standard ::、N8N_USER_FOLDER 与 N8N_ENCRYPTION_KEY
  • Security-Umgebungsvariablen:N8N_SECURE_COOKIE Standard true、N8N_ENFORCE_SETTINGS_FILE_PERMISSIONS Standard false
  • Docker volumes: Das Volume liegt auf dem Host /var/lib/docker/volumes/<名字>/_datasowie der Unterschied zwischen ihm und einem Bind-Mount
  • Die Tag-Liste von n8nio/n8n: ein Tag pro Version, Image-Digest und komprimierte Größe sind abrufbar
  • Install Docker Engine on Ubuntu: Vollständige Schritte für die offizielle apt-Quelle, wenn du kein One-Click-Skript verwenden willst, nimm diesen Weg

Letzte Aktualisierung: 2. November 2026, verwendet wurde n8n 2.43.7.

THE END