Docker verstehen & sicher self-hosten
Von „Was ist ein Container & warum" über das mentale Modell und die tägliche Praxis bis zum eigenen Dienst hinter HTTPS auf dem VPS. Roter Faden: wir hosten n8n Schritt für Schritt selbst — vom ersten docker run bis live unter eigener Domain. In 9 Stufen.
Worum geht's?
Docker packt eine Anwendung samt allem, was sie zum Laufen braucht, in einen Container — eine isolierte, überall gleich startende Einheit. Damit endet das berüchtigte „läuft bei mir, aber nicht bei dir": derselbe Container läuft auf deinem Laptop wie auf dem Server.
Du lernst nicht nur Befehle, sondern das mentale Modell (Image, Container, Layer, Volume, Netzwerk), die tägliche Praxis, Compose für mehrere Dienste und ein eigenes Image — bis zum Self-Hosting hinter einem Reverse Proxy auf deinem eigenen Server.
Dieses Portal ist beides: Live-Präsentation für den Workshop und Selbstlern-Kurs zum Durchklicken. Dein Fortschritt wird lokal gespeichert.
? Für wen ist Docker wichtig?
Längst nicht nur für DevOps — überall, wo Software zuverlässig laufen und sauber betrieben werden soll.
🧠 Das mentale Modell in einem Bild
Ein Image ist die Vorlage (gestapelte, schreibgeschützte Schichten). Ein Container ist eine laufende Instanz davon.
n8n startenlaufender Prozess +
beschreibbare Schicht
Image = Vorlage, Container = laufende Instanz. Aus einem Image kannst du beliebig viele Container starten. Die unteren Schichten werden geteilt — das macht Images klein und Starts schnell.
🧵 Roter Faden: n8n selbst hosten
docker run (Stufe 4), dann Daten behalten (5), als Stack mit Datenbank (6), schließlich hinter HTTPS auf dem VPS (8). Genau so laufen echte Dienste in der Praxis — auch bei FL Pro.🗺️ Die 9 Stufen
Was ist Docker & wozu?
Warum „läuft bei mir, aber nicht bei dir" so oft passiert — und was ein Container stattdessen garantiert.
1 „Läuft bei mir, aber nicht bei dir"
Software braucht eine bestimmte Umgebung: die richtige Sprach-Version, Bibliotheken, Systempakete, Konfiguration. Fehlt auf dem Zielrechner etwas, läuft es nicht — oder schlimmer: anders.
- „Bei mir geht's doch!" — auf dem Server nicht
- Stundenlanges Installieren von Abhängigkeiten
- Zwei Tools wollen verschiedene Versionen derselben Bibliothek
- Das Server-Setup steckt nur in jemandes Kopf
- App + Umgebung in einem Container — überall gleich
- Ein Befehl startet alles, in Sekunden
- Jeder Container ist isoliert — keine Versionskonflikte
- Das Setup ist Text (Dockerfile/Compose) — versionierbar & reproduzierbar
2 Container vs. virtuelle Maschine
🖥️ Virtuelle Maschinen
🐳 Container
Container teilen sich den Kernel → MB statt GB, Start in Sekunden statt Minuten. Für die meisten Server-Dienste genau das Richtige.
3 Was du davon hast
✓ Geschafft, wenn du …
Geschichte & Ökosystem
Woher Container kommen — und wie Docker, OCI und die Tools zusammenhängen.
1 Der Zeitstrahl
Container sind keine Erfindung von Docker — Docker hat sie nur für alle einfach gemacht.
2 Engine, Desktop & Registries
Images leben in einer Registry: öffentlich auf Docker Hub oder GHCR (GitHub), oder in einer eigenen, self-gehosteten. docker pull lädt herunter, docker push lädt hoch — wie bei Git, nur für Images.
✓ Geschafft, wenn du …
Das mentale Modell
Fünf Begriffe — Image, Container, Layer, Volume, Netzwerk — und der Rest ergibt sich fast von selbst.
1 Image, Container & Layer
Das wichtigste Begriffspaar: ein Image ist die unveränderliche Vorlage, ein Container die laufende Instanz davon.
+ dünne, beschreibbare
Schicht obendrauf
Ein Image besteht aus schreibgeschützten Layern (grob: jede Bau-Anweisung = ein Layer). Beim Start legt Docker eine dünne beschreibbare Schicht obendrauf — das ist der Container. Mehrere Container teilen sich die unteren Layer.
2 Die Schlüsselbegriffe
- Image — die Vorlage (gestapelte Layer). Hat einen Tag, z. B.
postgres:16(Name:Version). - Container — eine laufende Instanz eines Images; bekommt einen Namen (
--name). - Registry — der „App-Store" für Images (Docker Hub, GHCR, eigene) —
pull/push. - Volume — persistenter Speicher außerhalb des Containers (Stufe 5). Ohne ihn sind Daten beim Löschen weg.
- Port-Mapping —
-p 5678:5678verbindet einen Host-Port mit einem Container-Port. - Netzwerk — Container im selben Netz erreichen sich über ihren Namen (wichtig für Compose, Stufe 6).
3 Der Lebenszyklus eines Containers
Vier Stationen — vom Image zum laufenden Container und wieder weg.
✓ Geschafft, wenn du …
Erster Container
Docker installieren (Windows / macOS / Linux) und gleich den ersten echten Dienst starten: n8n.
1 Docker installieren
Wähle oben deine Plattform — die Schritte passen sich an.
- Docker Desktop von docker.com installieren.
- Es richtet automatisch WSL2 ein (Windows-Subsystem für Linux) — bei Nachfrage zustimmen, ggf. einmal neu starten.
- Docker Desktop starten, bis das Wal-Symbol „running" zeigt.
- Docker Desktop für macOS (Apple Silicon oder Intel) von docker.com laden.
- App in den Programme-Ordner ziehen, starten, Rechte bestätigen.
- Docker Engine über das Paketsystem der Distro installieren (z. B. via dem Skript von docs.docker.com).
- Optional deinen Nutzer zur Gruppe
dockerhinzufügen und neu einloggen — dann geht's ohnesudo.
Versionsstand: Docker Engine / Desktop v27 · Stand Juni 2026. Die hier gezeigten Befehle sind seit Jahren stabil.
2 Den ersten echten Dienst starten: n8n
Genug Theorie — wir starten unseren roten Faden. Ein Befehl, und n8n läuft.
-d— „detached": läuft im Hintergrund, gibt das Terminal frei.--name n8n— ein merkbarer Name statt einer zufälligen ID.-p 5678:5678— Host-Port 5678 → Container-Port 5678.
http://localhost:5678 öffnen — n8n begrüßt dich. 🎉 Das ist der Faden, den wir Stufe für Stufe ausbauen.3 Container im Griff: die Grundbefehle
docker ps # laufende Container (mit -a: auch gestoppte) docker logs -f n8n # Live-Logs ansehen docker exec -it n8n sh # eine Shell IM Container öffnen docker stop n8n # anhalten docker start n8n # wieder starten docker rm -f n8n # entfernen (erzwingt Stop) docker images # geladene Images
docker logs ist dein erster Griff, wenn etwas nicht läuft — die Antwort steht fast immer dort.4 Claude Code kennt die Befehle
Du musst dir die Flags nicht merken — beschreibe einfach, was du willst.
Starte mir n8n als Container im Hintergrund auf Port 5678.
Klar: docker run -d --name n8n -p 5678:5678 docker.n8n.io/n8nio/n8n. Soll ich es ausführen und prüfen, ob es unter localhost:5678 antwortet?
✓ Geschafft, wenn du …
Daten behalten
Container sind wegwerfbar — Daten dürfen es nicht sein. Volumes, Bind-Mounts, Env & Ports.
1 Warum Daten verschwinden
Alles, was ein Container schreibt, lebt in seiner dünnen, beschreibbaren Schicht — und die stirbt mit dem Container.
- n8n schreibt Workflows in den Container
docker rm n8n→ alles weg- Update = neuer Container = Datenverlust
- Daten liegen außerhalb des Containers
- Container löschen/neu bauen — Daten bleiben
- Updates & Backups problemlos
Merksatz: Container sind wegwerfbar, Volumes sind wertvoll. Alles, was bleiben soll, gehört in ein Volume.
2 Named Volume vs. Bind-Mount
Zwei Wege, Daten persistent zu machen — beide über -v.
-v n8n_data:/home/node/.n8n- Docker verwaltet den Speicherort
- Ideal für Dienst-Daten (DB, App-State)
-v ./config:/app/config- Ein echter Ordner von deinem Host
- Ideal für Config, die du selbst editieren willst
n8n persistent starten:
3 Umgebung & Ports konfigurieren
-e KEY=wert— Umgebungsvariablen (Zeitzone, DB-Zugang, Feature-Flags). Die übliche Art, einen Container zu konfigurieren.-p 8080:80— Host-Port 8080 zeigt auf Container-Port 80. Links Host, rechts Container.--restart unless-stopped— Container startet nach einem Reboot automatisch wieder (wichtig für Server, Stufe 8).
-v, -e und -p in einem immer länger werdenden docker run? Genau dann lohnt sich Compose — die nächste Stufe.✓ Geschafft, wenn du …
Compose: mehrere Container als Stack
Echte Dienste bestehen aus mehreren Containern. Compose beschreibt sie als Text — ein Befehl startet alles.
1 Vom langen run zur compose.yml
n8n soll seine Daten in eine richtige Datenbank schreiben? Dann brauchst du zwei Container, die zusammenspielen. Statt zweier langer docker run-Befehle: eine Datei.
services: postgres: image: postgres:16 restart: unless-stopped environment: POSTGRES_DB: n8n POSTGRES_USER: n8n POSTGRES_PASSWORD: changeme # Platzhalter! volumes: [ "pg_data:/var/lib/postgresql/data" ] n8n: image: docker.n8n.io/n8nio/n8n restart: unless-stopped depends_on: [ postgres ] ports: [ "5678:5678" ] environment: DB_TYPE: postgresdb DB_POSTGRESDB_HOST: postgres # = Service-Name! DB_POSTGRESDB_PASSWORD: changeme volumes: [ "n8n_data:/home/node/.n8n" ] volumes: pg_data: n8n_data:
postgres — Compose legt dafür automatisch ein gemeinsames Netzwerk an. Die Passwörter sind Platzhalter (changeme); echte Secrets gehören in eine .env (Stufe 9).2 Der Stack als Bild
Zwei Services in einem Netz, jeder mit seinem Volume. Nur n8n veröffentlicht einen Port nach außen; die Datenbank bleibt intern — sicherer.
3 Den Stack bedienen
docker compose up -d # alle Services im Hintergrund starten docker compose ps # Status des Stacks docker compose logs -f # Logs aller Services live docker compose down # stoppen & entfernen (Volumes bleiben!)
down entfernt Container & Netz, aber nicht die named Volumes — deine Daten bleiben. Erst down -v löscht auch die Volumes.✓ Geschafft, wenn du …
Eigenes Image bauen
Fertige Images decken viel ab. Für deinen eigenen Code schreibst du ein kurzes Dockerfile — und baust dein Image selbst.
1 Fertiges Image nutzen oder selbst bauen?
Die meiste Zeit nimmst du fertige Images (n8n, Postgres, nginx …). Ein eigenes Image baust du für deinen eigenen Code.
- Standard-Software (Datenbanken, Tools, Dienste)
- Einfach
image:in der compose.yml - Wird vom Hersteller gepflegt & aktualisiert
- Deine App / Website / dein Skript
- Du schreibst ein Dockerfile
docker builderzeugt dein Image
2 Das Dockerfile
Ein Dockerfile ist ein Rezept: Basis-Image wählen, eigene Dateien hineinkopieren, Startbefehl setzen. Beispiel: eine statische Website (z. B. die aus der Web-Schulung) in ein winziges nginx-Image packen.
FROM nginx:alpine # schlankes Basis-Image COPY ./site /usr/share/nginx/html # deine Dateien hinein # nginx startet automatisch — kein CMD nötig
build den Cache.3 Tags, .dockerignore & wann neu bauen
- Tag — versioniere dein Image:
docker build -t meine-site:1.2 ..latestist nur ein bewegliches Etikett. .dockerignore— wie.gitignore: hältnode_modules,.gitund Secrets aus dem Image (kleiner & sicherer).- Neu bauen nach jeder Code-Änderung. In der compose.yml bindest du es per
build: .stattimage:ein.
✓ Geschafft, wenn du …
Auf den VPS
Den n8n-Stack auf deinen Server bringen, hinter HTTPS unter eigener Domain — und sauber im Betrieb halten.
1 Den Stack auf den Server bringen
Auf einem VPS ist Docker dasselbe wie lokal — nur per SSH. Du legst die compose.yml aus Stufe 6 in einen Ordner und startest sie.
restart: unless-stopped in der compose.yml sorgt dafür, dass deine Dienste nach einem Server-Reboot von selbst wieder hochkommen.2 Reverse Proxy: HTTPS & Domain
Niemand soll :5678 tippen. Ein Reverse Proxy nimmt Anfragen auf n8n.deinedomain.de entgegen, kümmert sich um HTTPS und reicht sie an den Container weiter.
Der Proxy holt automatisch ein Let's-Encrypt-Zertifikat. Mit Caddy reichen drei Zeilen:
n8n.deinedomain.de {
reverse_proxy localhost:5678
}
n8n.deinedomain.de → deine Server-IP. Alternativ per Web-UI: der Nginx Proxy Manager — genau das Setup, das auch bei FL Pro läuft.3 Betrieb: Updates & Backups
Zwei Handgriffe, die du regelmäßig brauchst.
docker compose pull # neue Images holen docker compose up -d # Container mit neuen Images neu erstellen
docker run --rm -v n8n_data:/data -v $PWD:/backup busybox \
tar czf /backup/n8n-backup.tgz /data
.tgz-Datei. Diese regelmäßig (z. B. per Cron) wegkopieren — dann ist dein Dienst jederzeit wiederherstellbar.✓ Geschafft, wenn du …
Sicherheit & Claude Code
Die paar Regeln, die einen self-gehosteten Dienst sicher machen — und wie Claude Code dir im Docker-Alltag hilft.
1 Sichere Defaults
Die meisten Sicherheitsprobleme entstehen aus wenigen, vermeidbaren Fehlern. Diese vier Regeln decken das Wichtigste ab:
.env reingeben — nie ins Dockerfile/Image backen.USER im Dockerfile).-p nach außen).pullen; gepflegte Tags statt uraltem latest.2 Secrets via .env & Aufräumen
Statt Passwörter in die compose.yml zu schreiben, legst du sie in eine .env daneben (die nicht ins Git-Repo gehört):
POSTGRES_PASSWORD=ein-langes-zufälliges-passwort N8N_ENCRYPTION_KEY=…
${POSTGRES_PASSWORD}. So liegt kein Klartext-Secret im versionierten Text.docker system prune entfernt ungenutzte Container, Netze & Images und gibt Plattenplatz frei (mit -a gründlicher — auf Servern bewusst einsetzen).3 Claude Code als Docker-Helfer
Compose-Dateien, Dockerfiles, kryptische Fehler — beschreibe das Problem, statt zu googeln.
Mein n8n-Container startet nicht — hier die Logs. Was ist los?
Die Logs zeigen „connection refused" zur DB: n8n startet, bevor Postgres bereit ist. Ich ergänze einen Healthcheck + depends_on: condition: service_healthy. Soll ich die compose.yml anpassen?
✓ Geschafft, wenn du …
Docker-Cheat-Sheet
Die wichtigsten Befehle zum Mitnehmen. (Zählt nicht für den Fortschritt.)
▶ Container-Alltag
docker ps -adocker logs -f <n>docker exec -it <n> shdocker run -d -p H:Cdocker stop/rm <n>docker images🧩 Compose & Images
docker compose up -ddocker compose downdocker compose logs -fdocker compose pulldocker build -t x .docker system prune★ Gute Gewohnheiten
- Alles, was bleiben soll, in ein Volume — Container sind wegwerfbar.
- Secrets in eine
.env, nie ins Image;.dockerignorefrüh pflegen. - Feste Image-Tags (z. B.
postgres:16) statt blindlatest. - Nach außen nur, was nötig ist — Datenbanken hinter dem Reverse Proxy lassen.
Quiz
10 Fragen quer durch die Stufen. Ab 8 richtigen Antworten schaltest du dein Zertifikat frei.
Dein Zertifikat
Glückwunsch! Trage deinen Namen ein und drucke das Zertifikat (oder speichere als PDF).