Plattform:
Tages-Workshop

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.

🧰
Selbstmacher & KMU
Eigene Tools (n8n, Wikis, Dashboards) datensouverän selbst betreiben.
💻
Entwickler:innen
„Läuft bei mir" beenden — reproduzierbare Umgebungen, eigene Images.
⚙️
DevOps / Admins
Dienste isolieren, orchestrieren, sauber updaten & sichern.
📊
Data Scientists
Reproduzierbare Stacks (DB + Notebook + Modell) per Compose.
🌍
Souveränität
KI & Tools auf dem eigenen Server statt in der US-Cloud.
🤖
Claude-Code-Nutzer
Dockerfile & Compose mit Claude Code schreiben und debuggen (Stufe 9).

🧠 Das mentale Modell in einem Bild

Ein Image ist die Vorlage (gestapelte, schreibgeschützte Schichten). Ein Container ist eine laufende Instanz davon.

Skizze
🐳 Container
laufender 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

Ein echter Dienst end-to-end: Wir nehmen n8n (quelloffene Automatisierung) und bauen es Stufe für Stufe aus — erst 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

Voraussetzung nur Terminal-Grundlagen (siehe Schulung Terminal-Basics). Keine Docker-Vorkenntnisse nötig. Module 1–5 funktionieren auch als kompakter Halbtag.
Stufe 1

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.

✗ Ohne Docker
  • „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
✓ Mit Docker
  • 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

Ein Container verpackt eine App mit allen Abhängigkeiten und teilt sich den Kernel des Host-Systems. Eine VM bringt dagegen ein komplettes eigenes Betriebssystem mit — viel schwerer und langsamer.
Skizze

🖥️ Virtuelle Maschinen

App A
Gast-OS (komplett)
App B
Gast-OS (komplett)
Hypervisor
Host-Hardware

🐳 Container

App A
App B
App C
Docker Engine
geteilter Host-Kernel
Host-Hardware

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

📦
Reproduzierbar
Gleiches Image = gleiches Verhalten auf Laptop, CI und Server.
🧱
Isoliert
Jeder Dienst in seinem Container — keine Versions- oder Port-Konflikte.
🚀
Schnell & leicht
Start in Sekunden, MB statt GB — viele Container auf einem Server.
🌍
Portabel
Läuft überall, wo Docker läuft — und macht Self-Hosting einfach.

✓ Geschafft, wenn du …

Stufe 2

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.

1979chroot
Unix kann Prozesse in einen eigenen Datei-Unterbaum sperren — die Ur-Idee der Isolation.
2008LXC (Linux Containers)
Der Kernel bekommt Namespaces & cgroups — echte Container, aber sperrig zu bedienen.
2013Docker
Macht Container per einfachem CLI + Image-Format massentauglich. „Build, ship, run."
2015OCI & containerd
Offene Standards für Image- & Laufzeit-Format — Docker ist nicht mehr allein, alle bleiben kompatibel.
2018+Podman & Co.
Alternativen ohne Daemon/root. Gleiche Images, gleiche Befehle — dank OCI austauschbar.
HeuteStandard für Server-Software
Vom Laptop bis Kubernetes: Container sind die übliche Art, Dienste auszuliefern und zu betreiben.

2 Engine, Desktop & Registries

Docker Engine ist der Kern (Daemon + CLI), läuft nativ auf Linux. Docker Desktop ist die Komfort-App für Windows/macOS (bringt unter der Haube eine kleine Linux-VM mit) — für größere Firmen kostenpflichtig.

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 …

Stufe 3

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.

Skizze
🐳 Container
+ 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:5678 verbindet 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.

Lebenszyklus
docker run nginx # Image → neuer Container, startet docker ps # läuft er? (laufende Container) docker stop web # anhalten (Container bleibt bestehen) docker rm web # endgültig entfernen
Container sind „ephemer". Wird ein Container gelöscht, ist alles weg, was darin geschrieben wurde — es sei denn, du hast ein Volume benutzt. Genau darum geht es in Stufe 5.

✓ Geschafft, wenn du …

Stufe 4

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.

  1. Docker Desktop von docker.com installieren.
  2. Es richtet automatisch WSL2 ein (Windows-Subsystem für Linux) — bei Nachfrage zustimmen, ggf. einmal neu starten.
  3. Docker Desktop starten, bis das Wal-Symbol „running" zeigt.
  1. Docker Desktop für macOS (Apple Silicon oder Intel) von docker.com laden.
  2. App in den Programme-Ordner ziehen, starten, Rechte bestätigen.
  1. Docker Engine über das Paketsystem der Distro installieren (z. B. via dem Skript von docs.docker.com).
  2. Optional deinen Nutzer zur Gruppe docker hinzufügen und neu einloggen — dann geht's ohne sudo.
Installation prüfen
docker --version Docker version 27.x, build … docker run hello-world Hello from Docker! Deine Installation funktioniert. ✓

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.

n8n starten
docker run -d --name n8n -p 5678:5678 docker.n8n.io/n8nio/n8n Unable to find image locally — pulling … ✓ a1b2c3d4e5f6 (Container läuft im Hintergrund)
  • -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.
Jetzt im Browser 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

🐳Die Handvoll, die du täglich brauchst
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
Tipp: 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.

Du

Starte mir n8n als Container im Hintergrund auf Port 5678.

Claude Code

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 …

Stufe 5

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.

Skizze
✗ Ohne Volume
  • n8n schreibt Workflows in den Container
  • docker rm n8n → alles weg
  • Update = neuer Container = Datenverlust
✓ Mit Volume
  • 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.

📦 Named Volume
  • -v n8n_data:/home/node/.n8n
  • Docker verwaltet den Speicherort
  • Ideal für Dienst-Daten (DB, App-State)
📁 Bind-Mount
  • -v ./config:/app/config
  • Ein echter Ordner von deinem Host
  • Ideal für Config, die du selbst editieren willst

n8n persistent starten:

n8n mit Volume
docker run -d --name n8n -p 5678:5678 \ -v n8n_data:/home/node/.n8n \ -e GENERIC_TIMEZONE=Europe/Berlin \ docker.n8n.io/n8nio/n8n # Jetzt übersteht n8n ein docker rm + Neustart ✓

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).
Viele -v, -e und -p in einem immer länger werdenden docker run? Genau dann lohnt sich Compose — die nächste Stufe.

✓ Geschafft, wenn du …

Stufe 6

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.

🐳docker-compose.yml — n8n + Postgres
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:
Wichtig: n8n erreicht die Datenbank einfach unter dem Service-Namen 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

Skizze
n8n
Port 5678 → außen
postgres
nur intern
gemeinsames Netz — erreichbar über Service-Namen
📦 n8n_data 📦 pg_data

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

Im Ordner mit der compose.yml
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 …

Stufe 7

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.

📥 Fertiges Image
  • Standard-Software (Datenbanken, Tools, Dienste)
  • Einfach image: in der compose.yml
  • Wird vom Hersteller gepflegt & aktualisiert
🔨 Eigenes Image
  • Deine App / Website / dein Skript
  • Du schreibst ein Dockerfile
  • docker build erzeugt 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.

📄Dockerfile
FROM nginx:alpine                  # schlankes Basis-Image
COPY ./site /usr/share/nginx/html   # deine Dateien hinein
# nginx startet automatisch — kein CMD nötig
Jede Zeile wird ein Layer. Reihenfolge clever wählen: was sich selten ändert (Basis, Abhängigkeiten) nach oben — dann nutzt build den Cache.
build & run
docker build -t meine-site . → Image „meine-site:latest" gebaut ✓ docker run -d -p 8080:80 meine-site # Website läuft auf http://localhost:8080

3 Tags, .dockerignore & wann neu bauen

  • Tag — versioniere dein Image: docker build -t meine-site:1.2 .. latest ist nur ein bewegliches Etikett.
  • .dockerignore — wie .gitignore: hält node_modules, .git und Secrets aus dem Image (kleiner & sicherer).
  • Neu bauen nach jeder Code-Änderung. In der compose.yml bindest du es per build: . statt image: ein.
Claude Code hilft: „Schreib mir ein Dockerfile für diese Vite-App" oder „warum ist mein Image so groß?" — gerade bei Multi-Stage-Builds ein echter Zeitgewinn.

✓ Geschafft, wenn du …

Stufe 8

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.

Terminal — auf dem VPS (per SSH)
ssh root@dein-server mkdir n8n && cd n8n nano docker-compose.yml # die compose.yml aus Stufe 6 einfügen docker compose up -d ✔ postgres started ✔ n8n started
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.

Skizze
Browsern8n.deinedomain.de
Reverse ProxyCaddy / NPM :443
Containern8n :5678

Der Proxy holt automatisch ein Let's-Encrypt-Zertifikat. Mit Caddy reichen drei Zeilen:

🔒Caddyfile
n8n.deinedomain.de {
    reverse_proxy localhost:5678
}
Voraussetzung: ein DNS-Eintrag 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.

🔄Update auf neue Versionen
docker compose pull        # neue Images holen
docker compose up -d       # Container mit neuen Images neu erstellen
Dank Volumes bleiben deine Daten beim Update erhalten — nur die Container werden ersetzt.
💾Volume sichern (Backup)
docker run --rm -v n8n_data:/data -v $PWD:/backup busybox \
  tar czf /backup/n8n-backup.tgz /data
Sichert das Volume in eine .tgz-Datei. Diese regelmäßig (z. B. per Cron) wegkopieren — dann ist dein Dienst jederzeit wiederherstellbar.
Geschafft: n8n läuft jetzt live unter deiner Domain, hinter HTTPS, mit persistenten Daten und Auto-Restart — genau so betreibt FL Pro seine Dienste.

✓ Geschafft, wenn du …

Stufe 9

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:

🔑
Keine Secrets im Image
Passwörter/Keys über .env reingeben — nie ins Dockerfile/Image backen.
👤
Nicht als root
Container möglichst als unprivilegierter Nutzer laufen lassen (USER im Dockerfile).
🚪
Ports nicht offen
Nur der Reverse Proxy ist erreichbar; Datenbanken bleiben intern (kein -p nach außen).
🔄
Aktuell halten
Images regelmäßig 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):

🔑.env (neben der compose.yml, in .gitignore)
POSTGRES_PASSWORD=ein-langes-zufälliges-passwort
N8N_ENCRYPTION_KEY=
In der compose.yml referenzierst du sie als ${POSTGRES_PASSWORD}. So liegt kein Klartext-Secret im versionierten Text.
Aufräumen: 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.

Du

Mein n8n-Container startet nicht — hier die Logs. Was ist los?

Claude Code

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?

Wie es weitergeht: Docker ist das Fundament des Tracks Souveräne IT / Self-Hosting. Als Nächstes: n8n richtig nutzen, lokale & souveräne KI und IT-Sicherheit — alles baut auf dem auf, was du hier gelernt hast. Mehr zum Bauen mit dem Agenten in der Claude-Code-Schulung.

✓ Geschafft, wenn du …

Bonus

Docker-Cheat-Sheet

Die wichtigsten Befehle zum Mitnehmen. (Zählt nicht für den Fortschritt.)

Container-Alltag

docker ps -a
Alle Container (auch gestoppte).
docker logs -f <n>
Live-Logs — erster Griff bei Fehlern.
docker exec -it <n> sh
Shell im Container öffnen.
docker run -d -p H:C
Hintergrund + Port-Mapping.
docker stop/rm <n>
Anhalten / entfernen.
docker images
Geladene Images.

🧩 Compose & Images

docker compose up -d
Ganzen Stack starten.
docker compose down
Stack stoppen (Volumes bleiben).
docker compose logs -f
Logs aller Services.
docker compose pull
Neue Images holen (dann up -d).
docker build -t x .
Eigenes Image bauen.
docker system prune
Ungenutztes aufräumen.

Gute Gewohnheiten

  • Alles, was bleiben soll, in ein Volume — Container sind wegwerfbar.
  • Secrets in eine .env, nie ins Image; .dockerignore früh pflegen.
  • Feste Image-Tags (z. B. postgres:16) statt blind latest.
  • Nach außen nur, was nötig ist — Datenbanken hinter dem Reverse Proxy lassen.
Lernkontrolle

Quiz

10 Fragen quer durch die Stufen. Ab 8 richtigen Antworten schaltest du dein Zertifikat frei.

Frage 1 von 10
Abschluss

Dein Zertifikat

Glückwunsch! Trage deinen Namen ein und drucke das Zertifikat (oder speichere als PDF).

FL
Florian Ludwig
AI Consultant · Kutzschbach INNOVATIONS
Zertifikat
Docker
Hiermit wird bestätigt, dass
Dein Name hier
den Workshop „Docker verstehen & sicher self-hosten" erfolgreich abgeschlossen hat.
Datum
GEPRÜFT
Florian LudwigAI Consultant · Kutzschbach INNOVATIONS