Zum Inhalt

Container-Hosting (Docker-Extension)

Die Docker-Extension bringt Container-Hosting pro Website ins Panel — auf Basis von rootless Podman, isoliert und ohne Docker-Daemon by default. Sie wird als Opt-in-Extension über den Marktplatz installiert; der Panel-Kern bleibt unberührt, solange sie nicht aktiviert ist.

Architektur in einem Satz

Ein Container ist ein neuer Website-App-Typ (neben PHP, Node.js, Python, Statisch), an genau eine Website gebunden. Er läuft rootless als der Linux-User dieser Website, ist nur über den nginx-Domain-Proxy der eigenen Website erreichbar (Port intern auf 127.0.0.1), und wird über eine eigene Seite Container in der Sidebar verwaltet.

Installation & Freigabe

  1. Extension aktivieren (Marktplatz) — installiert die Runtime nur auf den gewählten Servern: Podman + die rootless-Helfer (uidmap, fuse-overlayfs, passt) und den CVE-Scanner Grype. Das erfüllt „kein Docker-Daemon by default".
  2. Paket-Permission — im Paket legt der Admin mit Container-Hosting erlauben (perm_docker) fest, ob ein Kunde Container nutzen darf, plus Limits: Container, RAM je Container (MB), CPUs je Container, Disk je Container (GB) (jeweils 0 = unbegrenzt).

Einen Container betreiben

  1. Website vom Typ „Container" anlegen (unter Websites). Sie bekommt automatisch einen internen Port und eine nginx-Proxy-Regel: Domain → 127.0.0.1:<Port>.
  2. Auf der Seite Container ein Image bereitstellen (Image aus einer erlaubten Registry, interner Port des Containers, optionale Umgebungsvariablen). Danach: Start / Stopp / Neustart / Entfernen, Live-Status/Health und Logs.

Sicherheitsmodell (rootless, ehrlich)

Jeder Container läuft mit:

  • Rootless / User-Namespace pro Website (eigene subuid/subgid-Range) — nie Host-Root.
  • --cap-drop=ALL plus minimaler Allowlist (CHOWN, SETUID, SETGID, NET_BIND_SERVICE), --security-opt=no-new-privileges.
  • seccomp Default-Deny-Profil (Podman-Standard, zusätzlich explizit gepinnt).
  • Ressourcen-Limits aus dem Paket (--memory, --cpus, --pids-limit).
  • Netzwerk: Port nur auf 127.0.0.1 veröffentlicht (nur über den eigenen Domain-Proxy erreichbar); Host-Isolation via --no-map-gw (der Container kann keine Host-Dienste über das Gateway erreichen — SSRF/Lateral-Movement-Schutz); der bestehende SMTP-Egress-Block (Port 25) verhindert Direkt-zu-MX-Spam.

Grenzen des rootless-Modells (keine Schönfärberei)

  • AppArmor wird auf Container nicht angewandt: rootless Podman kann kein AppArmor-Profil laden (fehlendes CAP_MAC_ADMIN). Die Kernel-Ebene wird durch seccomp + Caps + User-Namespace abgesichert.
  • Shared Kernel: rootless-Container teilen sich wie alles auf einem Single-Kernel-System den Kernel — ein Kernel-Privesc-CVE betrifft alle. Stärkere Isolation (gVisor/Sysbox) ist eine mögliche Phase-2-Option mit Performance-Preis.

CVE-Pull-Gate (Grype)

Vor dem Start wird jedes Image mit Grype gescannt; das Ergebnis (Anzahl je Schweregrad) hängt an jeder Deploy-Antwort. Über die Panel-Einstellung container_cve_gate wird das Verhalten gesteuert:

  • off (Standard) — nur scannen und anzeigen, nie blockieren.
  • critical — Deploy blockieren, wenn kritische CVEs vorhanden sind.
  • fixable-critical — nur blockieren, wenn kritische CVEs mit verfügbarem Fix vorhanden sind.

Admins/Reseller können einen Block mit force überschreiben; Kunden nicht. Bei kritischen CVEs im Image wird die Benachrichtigung container_vulnerability_detected an Admin und Kunde ausgelöst.

Im Security Advisor → CRA-Tab zeigt eine „Container-CVEs"-Karte, die jedes bereitgestellte Container-Image mit Grype neu scannt und die Schweregrad-Zähler je Website auflistet. Die Karte erscheint nur, wenn die Docker-Extension aktiviert ist.

Abhängigkeiten & später hinzugefügte Server

Beim Aktivieren der Extension wird die Runtime an alle aktiven Server ausgerollt und idempotent installiert (Podman + rootless-Helfer + Grype + subordinate-id-Ranges). Ein nach der Aktivierung hinzugefügter Server erhält diesen Fan-out nicht — daher installiert der Agent Podman beim ersten Container-Deploy selbst (und füllt subuid/subgid nach), statt zu scheitern. Ergebnis: Jeder Server, der jemals einen Container hostet, hat die vollständige Runtime — egal ob bei Aktivierung vorhanden oder später hinzugefügt.

Backups & Aufräumen

  • Definition (Image + Env) wird auf der Website gespeichert → Teil des Panel-/DB-Backups und in der UI vorbelegt.
  • Container-Daten (Volumes/Storage) liegen im Home der Website → werden vom normalen Datei-Backup der Website erfasst.
  • Aufräumen: Beim Löschen der Website (oder des Kunden) wird der Container sauber gestoppt+entfernt, die Lingering-Session deaktiviert und die subuid-Range freigegeben — keine verwaisten Container.

Registry-Allowlist & Image-Verwaltung

  • Kuratierte Registry-Allowlist — die Extension-Einstellung container_registry_allowlist (kommagetrennt, leer = alle) beschränkt, aus welchen Registries Images stammen dürfen. Ein Deploy aus einer nicht gelisteten Registry wird abgewiesen (registry_not_allowed). Dockers implizite docker.io-Regel greift (nginxdocker.io).
  • Image-Verwaltung — die Container-Seite listet die lokalen Images je Website und bietet „Images bereinigen", um ungenutzte/verwaiste Images zu entfernen und Disk freizugeben, der gegen die Paket-Quota zählt.

Noch nicht enthalten (Phase 2)

  • Konsistente Volume-Snapshot-Backups + automatisches Re-Deploy beim Restore (aktuell: sauberes Re-Deploy aus der gespeicherten Definition; rootless-Storage lässt sich nicht 1:1 über Maschinen zurückspielen).
  • Optional gVisor/Sysbox für stärkere Isolation.