Debian 13 (Trixie): Container absichern & automatisiert betreiben (Teil 5)
Server gehärtet, Firewall steht, Backups laufen – jetzt kommen die Dienste. Teil 5 zeigt, wie du Docker-Container auf deinem Debian-13-Server sicher betreibst: Images, Rechte, Secrets, Updates und Stack-Backups im Zusammenspiel mit der Blog-Serie.
Warum Container-Härtung?
Mit Teil 1–4 ist der Host vorbereitet: Basis, Härtung, Firewall, Monitoring und Backups. In Teil 5 geht es um die eigentlichen Arbeitspferde – deine Container. Ein Container ist keine Sicherheitsgrenze an sich: Ohne Limits, Read-only-Dateisystem und saubere Rechtevergabe ist er nur ein bequemer Weg, Software auszuführen. Mit dem Grundgerüst aus diesem Artikel betreibst du Stacks, die den Härtungs-Standard aus Teil 2 und 3 fortsetzen.
Konzept: Isolation, Least Privilege, Automatisierung
Drei Grundsätze bestimmen den sicheren Container-Betrieb:
- Isolation: Jeder Dienst bekommt eigene Limits – CPU, RAM, Prozesse, Dateisystem.
- Least Privilege: Nur die Rechte, die der Dienst wirklich braucht – keine Root-Capabilities, kein Schreibzugriff, wo Lesen reicht.
- Automatisierung: Updates, Neustarts und Backups laufen geplant – nicht wenn du zufällig dran denkst.
Der Rest des Artikels setzt diese drei Punkte in konkrete Dateien und Befehle um.
Docker auf dem gehärteten Server installieren
Debian liefert docker.io mit, die offiziellen Pakete sind aber aktueller. Empfohlener Weg über das offizielle Docker-Repository:
curl -fsSL https://download.docker.com/linux/debian/gpg | sudo gpg --dearmor -o /usr/share/keyrings/docker.gpg
echo "deb [arch=amd64 signed-by=/usr/share/keyrings/docker.gpg] https://download.docker.com/linux/debian trixie stable" | sudo tee /etc/apt/sources.list.d/docker.list
sudo apt update
sudo apt install docker-ce docker-ce-cli containerd.io docker-compose-plugin
sudo systemctl enable --now docker
docker angehört, hat faktisch Root-Rechte auf dem Host. Mitglieder nur aufnehmen, wenn es wirklich nötig ist – die saubere Alternative ist Rootless (Ausblick in Teil 6).Container härten: Das sichere Compose-Grundgerüst
Dieses Grundgerüst lässt sich auf fast jeden Dienst aus der Blog-Serie übertragen:
services:
app:
image: beispiel/app:latest
restart: unless-stopped
read_only: true
tmpfs:
- /tmp
security_opt:
- no-new-privileges=true
cap_drop:
- ALL
pids_limit: 100
deploy:
resources:
limits:
cpus: "1.0"
memory: 1G
- read_only: Das Root-Dateisystem ist schreibgeschützt – Schreibpfade werden einzeln als Volume oder tmpfs freigegeben.
- cap_drop ALL: Der Container startet ohne Linux-Capabilities. Braucht ein Dienst eine (z. B.
NET_BIND_SERVICEfür Ports unter 1024), wird sie gezielt wieder ergänzt. - pids_limit: Begrenzt Prozesse – schützt vor Fork-Bombs im Container.
- deploy.limits: CPU- und RAM-Limits wie in allen Artikeln der Serie.
Wichtig: Nicht jeder Dienst verträgt read_only sofort – beim Ausrollen Logs prüfen und Ausnahme-Pfade dokumentieren, statt den Schutz wieder komplett zu entfernen.
Secrets statt Klartext-Passwörter
In den Blog-Artikeln tauchen Passwörter immer wieder direkt in der Compose-Datei auf – für den Produktivbetrieb gehört das in eine geschützte .env-Datei:
# Datei: .env (im Stack-Ordner)
DB_PASSWORD=MeinGeheimesPasswort
# lange, zufällige Zeichenkette erzeugen:
openssl rand -hex 32
# docker-compose.yml
services:
app:
environment:
- DB_PASSWORD=${DB_PASSWORD}
chmod 600 .envund die Datei nie in Git committen.- Werden mehrere Nutzer am Server gepflegt, ist ein Passwort-Manager die bessere Ablage als eine Datei.
- Env-Variablen sind im laufenden Container für jeden lesbar, der
docker inspectdarf – für echte Geheimnisse später Docker Secrets (Ausblick Teil 6).
Updates: selektiv mit Watchtower
Automatische Updates gab es in Teil 2 für den Host – für Container übernimmt das Watchtower. Der wichtigste Punkt aus dem Blog-Artikel: selektiv arbeiten.
services:
watchtower:
image: containrrr/watchtower
command: --cleanup --schedule "0 4 * * *"
volumes:
- /var/run/docker.sock:/var/run/docker.sock
- Labels nur dort setzen, wo ein Neustart gefahrlos ist:
com.centurylinklabs.watchtower.enable=true. - Datenbanken und Stateful-Dienste von der Automatik ausnehmen.
- Images pinnen (z. B.
image: app:2.3.1) statt blindlatest– Updates werden so zu bewussten Schritten.
Stack-Backups: Volumes & Compose-Dateien
Ein Container-Backup besteht aus zwei Teilen: den Compose-Dateien (Konfiguration) und den Volumes/Bind-Mounts (Daten). Die Compose-Dateien sind schnell gesichert:
sudo tar -czf /srv/backup/stacks-2026-09-06.tar.gz -C /opt stacks
Für Volumes gibt es zwei Wege: entweder grafisch mit Duplicati (Artikel) oder direkt im Borg-Workflow aus Teil 4 – am sichersten mit gestoppten Containern. Wichtig: docker compose stop hält die Dienste nur an und lässt Container und Netzwerke intakt – docker compose down würde sie erst löschen und die Ausfallzeit unnötig verlängern:
#!/bin/sh
cd /opt/stacks/app || exit 1
# Dienste anhalten – Container & Netzwerke bleiben erhalten
docker compose stop
# Notbremse: Egal ob das Backup klappt oder nicht – die Container starten wieder.
# borg create bricht bei Fehlern ab (z. B. volle Platte), dank trap läuft
# "docker compose start" in jedem Fall beim Verlassen des Skripts.
trap 'docker compose start' EXIT
# Archivname mit dynamischem Datum – keine Kollisionen am Folgetag
borg create --stats /mnt/backup/borg-repo::stack-app-$(date +%Y-%m-%d) /opt/stacks/app
borg prune --keep-daily 7 --keep-weekly 4 --keep-monthly 6
Monitoring & Ressourcen im Blick
Uptime Kuma aus der Blog-Serie überwacht die Dienste von außen – von innen kommen diese Checks dazu:
docker compose ps
docker stats --no-stream
docker logs --tail 100 app
docker statszeigt, ob die Limits aus Teil 5 realistisch sind oder ein Dienst an der RAM-Grenze arbeitet.- Uptime-Kuma-Monitore zusätzlich auf HTTP-Inhalte prüfen lassen, nicht nur auf „Port offen“.
- Wöchentlich
ss -tulpn(Teil 3) gegen die Liste der erwarteten Container-Ports abgleichen.
Häufige Probleme
| Problem | Lösung |
|---|---|
Container startet nicht mit read_only | Logs prüfen: fehlende Schreibpfade einzeln als Volume/tmpfs ergänzen – nicht den Schutz entfernen. |
| Dienst braucht Port unter 1024 | cap_add: [NET_BIND_SERVICE] ergänzen statt cap_drop zu entfernen. |
| Passwort steht noch in der Compose-Datei | In .env auslagern, Datei mit chmod 600, Stack neu erstellen. |
| Watchtower startet Datenbank neu | Label enable=false an stateful Container setzen und Updates manuell planen. |
| Backup scheint zu fehlen | Volumes sind nicht in ./backups – Mount-Pfade des Stacks prüfen und Restore testen. |
| docker-Gruppe wurde doch benötigt | Besser Rootless-Docker einrichten (Ausblick Teil 6) statt dauerhaft Root-Rechte zu verteilen. |
Fazit & Serien-Ende
Mit Teil 5 ist der Kreis geschlossen: Debian 13 wird installiert (Teil 1), gehärtet (Teil 2), abgeschottet (Teil 3), überwacht und gesichert (Teil 4) – und beherbergt jetzt Dienste, die nach denselben Standards laufen. Die Grundsätze lassen sich auf jeden Stack aus der Blog-Serie übertragen.
Weiter zu Teil 6: Rootless Docker, Podman, Docker Secrets & seccomp – Container im Produktivbetrieb.