> ## Content Index
> Fetch the complete content index at: https://blog.lange-it.com/llms.txt
> Use this file to discover other available public pages before exploring further.

# Docker-Host unter Ubuntu vorbereiten: Was ich kläre, bevor der erste Container läuft
- URL: https://blog.lange-it.com/docker-host-ubuntu-vorbereiten/
- Published: 2026-10-05T16:12:08.000Z
- Updated: 2026-10-05T16:12:08.000Z
- Description: Ein stabiler Docker-Host beginnt nicht mit docker compose up. Meine praktische Vorbereitung von Ubuntu, Storage, Netzwerk, Firewall, Rechten, Logging und Recovery.
- Author: Peter Lange
- Tags: Docker, Ubuntu, Security, Netzwerk, Selfhosting

## Der erste Container ist für mich nicht der Anfang

Einen Docker-Host aufzusetzen wirkt zunächst einfach: Ubuntu installieren, Docker Engine dazu, Compose-Datei kopieren und `docker compose up -d` ausführen.

Technisch kann das funktionieren. Für einen Host, auf dem später mehrere Dienste zuverlässig laufen sollen, beginne ich inzwischen aber früher.

Bevor der erste produktive Container startet, möchte ich wissen, wie der Host aktualisiert wird, wo persistente Daten liegen, welche Netze verwendet werden, welche Ports wirklich erreichbar sein sollen und wie ich das System sichern und wiederherstellen kann.

![Konzeptioneller Ablauf vom vorbereiteten Ubuntu-Host über Struktur, Netzwerk und Docker Engine bis zu Stacks, Betrieb und Recovery](https://blog.lange-it.com/content/images/2026/10/lange-it-blog-docker-host-vorbereitung-flow.png)

Diese Vorbereitung verhindert, dass die Infrastruktur erst dann ein Konzept bekommt, wenn bereits mehrere Anwendungen davon abhängen.

## Erst den Host sauber aufsetzen

Docker abstrahiert Anwendungen, aber nicht den darunterliegenden Server. Kernel, Dateisystem, Netzwerk, Uhrzeit und Paketverwaltung bleiben Teil der Plattform.

Ich beginne deshalb mit einer von Docker unterstützten Ubuntu-Version und einem vollständig aktualisierten Grundsystem. Welche Releases aktuell unterstützt werden, prüfe ich direkt in der Docker-Dokumentation.\[^1\]

Zur Basiskontrolle gehören für mich beispielsweise:

```bash
sudo apt update
sudo apt upgrade
timedatectl status
ip addr
ip route
df -h

```

Das ist keine vollständige Hardening-Checkliste. Ich möchte zunächst sicherstellen, dass Zeit, DNS, Routing und Storage nachvollziehbar funktionieren, bevor Docker eine weitere Netzwerkschicht hinzufügt.

Ubuntu verwendet `systemd-timesyncd` standardmäßig für die Zeitsynchronisation.\[^2\] Eine korrekte Uhr ist gerade bei Logs, Zertifikaten und der späteren Fehleranalyse wichtig.

Auch Updates plane ich bewusst. Ubuntu Server bringt `unattended-upgrades` für automatische Sicherheitsupdates mit; Canonical dokumentiert auch die Anpassungsmöglichkeiten.\[^3\] Ob und wann ein produktiver Host automatisch neu starten darf, bleibt für mich allerdings eine Betriebsentscheidung.

## Docker aus einer definierten Quelle installieren

Für einen produktiven Host bevorzuge ich einen nachvollziehbaren Installationsweg statt eines Installationsskripts aus einem alten Blogbeitrag.

Docker dokumentiert für Ubuntu die Installation über das offizielle `apt`\-Repository und nennt dort Voraussetzungen, unterstützte Ubuntu-Versionen und mögliche Paketkonflikte.\[^1\]

Wichtiger als eine Kopie aller aktuellen Installationsbefehle ist mir der Grundsatz:

![Konzeptioneller Ablauf von einer bekannten Docker-Installationsquelle über Updates bis zu nachvollziehbaren Versionsständen](https://blog.lange-it.com/content/images/2026/10/lange-it-blog-docker-installationsstrategie-flow.png)

Nach der Installation prüfe ich mindestens Engine und Compose-Plugin:

```bash
docker version
docker compose version
sudo systemctl status docker

```

## Eine Ordnerstruktur festlegen, bevor Anwendungen sie festlegen

Einer der einfachsten Schritte zahlt sich später besonders aus: Ich entscheide früh, wo Deployment-Dateien, persistente Daten und Sicherungen hingehören.

Ein mögliches generisches Modell sieht so aus:

```text
/srv/docker/
├── stacks/
│   ├── application-a/
│   └── application-b/
├── data/
├── backups/
└── shared/

```

Das ist ausdrücklich kein vorgeschriebener Docker-Standard. Auch andere zur eigenen Umgebung passende Strukturen können sinnvoll sein.

Wichtiger als der konkrete Pfad ist mir die Trennung der Verantwortlichkeiten. `stacks` kann Compose- und Deployment-Dateien enthalten, `data` bewusst auf dem Host abgelegte persistente Daten, `backups` einen Arbeitsbereich für Sicherungen und `shared` gezielt gemeinsam verwendete Ressourcen.

Eine Sicherung sollte natürlich nicht ausschließlich auf demselben Host verbleiben, dessen Ausfall sie absichern soll.

## Bind Mount oder Volume ist eine Betriebsentscheidung

Docker unterstützt sowohl Volumes als auch Bind Mounts. Volumes werden von Docker verwaltet; Bind Mounts verknüpfen einen expliziten Hostpfad mit dem Container.\[^4\]

Ich entscheide deshalb nicht pauschal, dass eines davon grundsätzlich besser ist.

Bei Bind Mounts muss ich Hostpfade, Eigentümer und Berechtigungen selbst sauber verwalten. Dafür ist die Lage der Daten unmittelbar sichtbar. Bei Docker Volumes übernimmt Docker mehr von der Speicherverwaltung. Trotzdem muss ich wissen, welche Volumes relevante Daten enthalten und wie sie gesichert werden.

Meine eigentliche Frage lautet:

**Wie sichere ich diese Daten, und wie stelle ich sie auf einem neuen Host wieder her?**

Wenn ich diese Frage beim Anlegen des Stacks nicht beantworten kann, verschiebe ich das Problem nur.

## Docker-Netzwerke plane ich vor den Stacks

Docker erzeugt Netzwerke sehr komfortabel. Gerade deshalb kann mit der Zeit ein unübersichtlicher Bestand entstehen.

Bevor mehrere Stacks produktiv werden, kläre ich unter anderem:

- Welche Container kommunizieren nur innerhalb eines Stacks?
- Welche Dienste müssen einen gemeinsamen Reverse Proxy erreichen?
- Welche Datenbanken oder Backends dürfen ausschließlich intern erreichbar sein?
- Welche Anwendungen benötigen ausgehenden Internetzugriff?
- Welche Adressbereiche werden bereits im LAN, in VPNs oder an anderen Standorten verwendet?

Der letzte Punkt wird gern unterschätzt. Ein automatisch gewähltes Docker-Subnetz kann später mit einem gerouteten Netz oder VPN kollidieren.

Ich muss deshalb nicht jedem Container eine feste IP geben. Innerhalb benutzerdefinierter Docker-Netze macht die Namensauflösung zwischen Diensten viele feste Adressen überflüssig. Den **Adressraum** des Hosts möchte ich trotzdem bewusst planen.

## Ein veröffentlichter Port ist eine Sicherheitsentscheidung

Bei Bridge-Netzen sind Container-Ports standardmäßig nicht von außerhalb des Hosts erreichbar. Erst Port Publishing macht sie über Hostadressen zugänglich.\[^5\]

Ein Mapping wie

```yaml
ports:
  - "8080:80"

```

veröffentlicht den Port ohne explizite Hostadresse standardmäßig auf den Hostadressen.\[^5\]

Deshalb veröffentliche ich nicht automatisch Datenbanken, Caches oder interne APIs, nur damit sie bequem aus dem Netzwerk erreichbar sind.

**Intern kommunizieren, extern nur gezielt veröffentlichen.**

Ein Reverse Proxy kann so zum bewusst definierten Eintrittspunkt werden, während Backend-Dienste ausschließlich in Docker-Netzen erreichbar bleiben.

## Docker und Host-Firewall gemeinsam betrachten

Das ist einer der Punkte, die ich vor dem ersten produktiven Stack verstehen möchte.

Docker erzeugt auf Linux selbst Firewall-Regeln für Bridge-Netze, Port Publishing und NAT. Die offizielle Dokumentation warnt ausdrücklich davor, davon auszugehen, dass veröffentlichte Container-Ports von `ufw` genauso behandelt werden wie normale Host-Dienste: Docker kann den Verkehr vor den von `ufw` verwendeten INPUT- und OUTPUT-Ketten umleiten.\[^6\]

Das bedeutet nicht, dass eine Host-Firewall nutzlos ist. Es bedeutet, dass ich **Docker-Netzwerk und Host-Firewall als gemeinsames System** planen muss.

Beim iptables-Backend stellt Docker unter anderem die `DOCKER-USER`\-Chain bereit, in der eigene Filterregeln vor Dockers Forwarding-Regeln verarbeitet werden können.\[^7\]

Gleichzeitig entwickelt sich dieser Bereich weiter. Docker unterstützt inzwischen auch ein nftables-Backend, das in der aktuellen Dokumentation noch als experimentell gekennzeichnet ist und keine `DOCKER-USER`\-Chain bereitstellt.\[^8\]

Deshalb übernehme ich keine Firewall-Regelsammlung aus einem älteren Tutorial ungeprüft auf einen neuen Host.

## Den Docker-Daemon wie Root-Zugriff behandeln

Docker weist selbst darauf hin, dass Mitglieder der `docker`\-Gruppe Root-Level-Privilegien erhalten.\[^9\] Wer den Docker-Daemon kontrollieren kann, kann beispielsweise Hostverzeichnisse in Container einbinden und damit sehr weitreichend auf den Host zugreifen.\[^10\]

Deshalb ist

```bash
sudo usermod -aG docker <benutzer>

```

für mich keine harmlose Komforteinstellung, sondern eine bewusste Vergabe hochprivilegierter Rechte.

Dasselbe gilt für den Docker-Socket. `/var/run/docker.sock` in einen Container einzubinden kann praktisch sein, gibt diesem Container aber Zugriff auf eine sehr mächtige Verwaltungsschnittstelle.

## Secrets gehören nicht in die Compose-Datei

Ein Compose-Repository ist ein guter Ort für reproduzierbare Deployment-Definitionen. Es ist kein guter Ort für Klartext-Passwörter, API-Schlüssel oder private Schlüssel.

Ich trenne deshalb möglichst zwischen versionierbarer Konfiguration und geheimen Werten. Welche Secret-Verwaltung sinnvoll ist, hängt von der Umgebung ab; ein einzelner Docker-Host hat andere Anforderungen als Swarm, Kubernetes oder eine Plattform mit externem Secret Store.

**Deployment beschreiben, Secrets nicht versehentlich mit veröffentlichen oder versionieren.**

Auch eine `.env` ist nicht automatisch sicher, nur weil ihr Dateiname mit einem Punkt beginnt.

## Logging planen, bevor die Platte voll ist

Docker verwendet standardmäßig den `json-file` Logging Driver. Die Docker-Dokumentation weist darauf hin, dass dieser standardmäßig keine Log-Rotation durchführt und stark schreibende Container dadurch erheblichen Speicherplatz verbrauchen können. Docker empfiehlt für viele Fälle den `local` Logging Driver, der Rotation mitbringt.\[^11\]

Vor dem Produktivbetrieb möchte ich deshalb wissen, wie Container-Logs begrenzt oder zentral verarbeitet werden und wie freier Speicher überwacht wird.

```bash
docker system df
df -h

```

Ein automatisches `docker system prune -a` nach Zeitplan wäre dagegen keine pauschale Lösung. Aufräumen sollte ich erst, wenn klar ist, welche Artefakte tatsächlich entbehrlich sind.

## Ressourcen sind ebenfalls eine gemeinsame Host-Grenze

Container teilen sich CPU, RAM, Storage und Kernel des Hosts.

Docker setzt standardmäßig keine Ressourcenbegrenzung für Container; ein Container kann daher grundsätzlich so viele Hostressourcen verwenden, wie Kernel und Scheduler zulassen.\[^12\]

Nicht jeder kleine Dienst braucht sofort harte CPU- und RAM-Limits. Ich möchte aber wissen, welche Anwendung bei einem Fehler den gesamten Host beeinträchtigen könnte. Besonders Speicherknappheit ist relevant: Eine Out-of-Memory-Situation kann Auswirkungen weit über den verursachenden Container hinaus haben.\[^12\]

Monitoring des Hosts gehört deshalb genauso zum Docker-Betrieb wie der Blick auf einzelne Container.

## Neustart ist keine Update-Strategie

Eine Restart Policy kann einen Container nach einem Fehler oder Hostneustart wieder starten. Sie beantwortet aber nicht, wann ein Image aktualisiert werden soll, ob eine neue Version kompatibel ist oder wie ich nach einem fehlgeschlagenen Update zurückkehre.

Ich trenne deshalb drei Ebenen:

![Drei getrennt zu planende Update-Ebenen: Ubuntu und Kernel, Docker Engine sowie Container-Images und Anwendungen](https://blog.lange-it.com/content/images/2026/10/lange-it-blog-docker-host-update-flow.png)

Für jede Ebene brauche ich eine Vorstellung davon, wie Updates eingespielt und anschließend geprüft werden.

Blind jedes `latest`\-Image automatisch auszutauschen ist für mich genauso wenig ein Betriebskonzept wie einen Host jahrelang nicht zu aktualisieren.

## Backup und Recovery beginnen beim Aufbau

Eine saubere Hoststruktur hilft spätestens dann, wenn der ursprüngliche Server nicht mehr verfügbar ist.

Ich möchte unterscheiden können zwischen Dingen, die ich reproduzieren kann, und Dingen, die gesichert werden müssen.

Compose-Dateien kann ich versionieren. Images kann ich erneut aus einer Registry beziehen, sofern Versionen und Quelle bekannt sind. Persistente Anwendungsdaten müssen dagegen aus einer Sicherung kommen. Secrets müssen sicher verfügbar sein. Individuelle Hostkonfiguration muss dokumentiert oder automatisiert sein.

Das führt zu einer einfachen Frage:

**Könnte ich diesen Stack auf einem frischen Host wieder aufbauen, ohne auf dem alten Server nachsehen zu müssen?**

## Meine Preflight-Checkliste

| Bereich      | Frage                                                                       |
| ------------ | --------------------------------------------------------------------------- |
| Ubuntu       | Unterstützte Version, Updates und Zeit synchronisiert?                      |
| Installation | Docker aus einer nachvollziehbaren, gepflegten Quelle installiert?          |
| Storage      | Deployment und persistente Daten klar getrennt?                             |
| Netzwerk     | Docker-Adressräume geplant und konfliktfrei?                                |
| Exposition   | Nur tatsächlich benötigte Ports veröffentlicht?                             |
| Firewall     | Zusammenspiel von Docker und Host-Firewall verstanden und geprüft?          |
| Rechte       | Zugriff auf Docker-Daemon und Socket bewusst eingeschränkt?                 |
| Secrets      | Keine geheimen Werte versehentlich versioniert?                             |
| Logging      | Rotation bzw. Begrenzung und Storage-Überwachung vorgesehen?                |
| Ressourcen   | CPU, RAM und Plattenplatz des Hosts überwacht?                              |
| Updates      | Verfahren für Host, Docker Engine und Anwendungen definiert?                |
| Recovery     | Persistente Daten bekannt, gesichert und Wiederherstellung nachvollziehbar? |

Nicht jeder Host braucht dieselbe Architektur. Aber diese Fragen möchte ich beantworten, **bevor** aus einem Testsystem schleichend ein produktiver Server geworden ist.

## Docker macht Deployment einfach – Betrieb nicht automatisch

Docker nimmt mir viel Arbeit ab: reproduzierbare Container, isolierte Netzwerke, deklarative Compose-Dateien und komfortables Deployment.

Die Verantwortung für den Host verschwindet dadurch nicht.

Netzwerk, Firewall, Berechtigungen, Storage, Updates, Logging, Monitoring und Recovery bleiben Betriebsaufgaben. Wenn ich sie vor dem ersten Container strukturiere, muss ich sie später nicht zwischen bereits voneinander abhängigen Stacks nachträglich reparieren.

Deshalb beginnt ein Docker-Host für mich nicht mit:

```bash
docker compose up -d

```

Sondern mit der Frage:

**Wie soll dieser Host in einem Jahr noch verständlich, sicher aktualisierbar und wiederherstellbar sein?**

## Quellen

\[^1\]: Docker Docs, *Install Docker Engine on Ubuntu*: <https://docs.docker.com/engine/install/ubuntu/> \[^2\]: Ubuntu Server Documentation, *Synchronise time using timedatectl and timesyncd*: <https://documentation.ubuntu.com/server/how-to/networking/timedatectl-and-timesyncd/> \[^3\]: Ubuntu Security Documentation, *Security updates*: <https://documentation.ubuntu.com/security/security-updates/> \[^4\]: Docker Docs, *Storage*: <https://docs.docker.com/engine/storage/> \[^5\]: Docker Docs, *Port publishing and mapping*: <https://docs.docker.com/engine/network/port-publishing/> \[^6\]: Docker Docs, *Packet filtering and firewalls*: <https://docs.docker.com/engine/network/packet-filtering-firewalls/> \[^7\]: Docker Docs, *Docker with iptables*: <https://docs.docker.com/engine/network/firewall-iptables/> \[^8\]: Docker Docs, *Docker with nftables*: <https://docs.docker.com/engine/network/firewall-nftables/> \[^9\]: Docker Docs, *Linux post-installation steps*: <https://docs.docker.com/engine/install/linux-postinstall/> \[^10\]: Docker Docs, *Docker Engine security*: <https://docs.docker.com/engine/security/> \[^11\]: Docker Docs, *Configure logging drivers*: <https://docs.docker.com/engine/logging/configure/> \[^12\]: Docker Docs, *Resource constraints*: <https://docs.docker.com/engine/containers/resource%5Fconstraints/>