Podman 6.0: einen rootless Container als systemd-Service mit Quadlet betreiben
Wie Sie mit Podman 6.0 und Quadlet einen rootless Container als sauberen, autostart-fähigen systemd-Service betreiben – mit lauffähigem Caddy-Beispiel und den typischen Stolperfallen.
Wer von Docker Compose kommt, kennt das Muster: ein Container als Dienst, der beim Booten hochfährt und nach einem Absturz neu startet. Unter Podman übernimmt diese Rolle nicht Compose, sondern systemd – und seit einiger Zeit beschreibt man solche Dienste deklarativ mit Quadlet. Sie schreiben eine kurze .container-Datei, systemd generiert daraus eine vollwertige Service-Unit. In Podman 6.0 (Juni 2026) ist Quadlet der Standardweg und noch enger integriert. Dieser Beitrag stellt einen einzelnen rootless Dienst auf die Beine: eine .container-Datei ablegen, daemon-reload, starten, prüfen, autostart-fähig machen.
Was Quadlet macht – und wann es passt
Quadlet ist ein systemd-Generator, der zur Laufzeit aus einer .container-Datei eine .service-Unit erzeugt. Sie pflegen keine handgeschriebenen Units mit langen ExecStart=podman run ...-Zeilen mehr, sondern eine kompakte, ini-artige Beschreibung im vertrauten Compose-Stil (Image, Ports, Volumes, Umgebungsvariablen). Das passt genau dann, wenn Sie einen oder wenige Dienste auf einem Host rootless und autostart-fähig betreiben wollen – etwa auf einem VPS oder Self-Hosting-Server. Für Orchestrierung über mehrere Knoten bleibt Kubernetes das Mittel der Wahl.
Rootless bedeutet: Der Container läuft im User-Namespace Ihres normalen Logins, nicht als root. Entsprechend arbeiten wir durchgehend mit systemctl --user, nicht mit dem System-systemd.
Ein Hinweis zu Podman 6.0 vorweg: cgroup v1 wird nicht mehr unterstützt, ebenso wenig CNI, slirp4netns und iptables. Rootless-Netzwerk läuft über pasta, Firewalling über nftables. Auf einem aktuellen Linux (cgroup v2, netavark/pasta) ist das der Normalfall – auf sehr alten Hosts sollten Sie das vor dem Upgrade prüfen.
Der minimale Dienst
Wir betreiben einen einfachen Webserver (Caddy) als rootless Service. Legen Sie die Quadlet-Datei im rootless-Suchpfad ab:
mkdir -p ~/.config/containers/systemd
Datei ~/.config/containers/systemd/web.container:
[Unit]
Description=Caddy web server (rootless, Quadlet)
After=network-online.target
Wants=network-online.target
[Container]
Image=docker.io/library/caddy:2
PublishPort=8080:80
Volume=web-content:/usr/share/caddy:Z
Environment=TZ=UTC
[Service]
Restart=on-failure
[Install]
WantedBy=default.target
Danach den Generator einlesen lassen und den Dienst starten:
systemctl --user daemon-reload
systemctl --user start web.service
systemctl --user status web.service
status sollte active (running) zeigen. Ein kurzer Test:
curl -I http://localhost:8080
Caddy antwortet auf Port 8080; das benannte Volume web-content legt Podman beim ersten Start automatisch an.
Die Bausteine der .container-Datei
[Container]ist der Kern.Image=gibt das Image an (voll qualifiziert, inklusive Registry, um Mehrdeutigkeiten zu vermeiden).PublishPort=8080:80mappt Host-Port 8080 auf Container-Port 80.Volume=web-content:/usr/share/caddy:Zbindet ein benanntes Volume ein; das:Zsetzt das SELinux-Label passend, falls Ihr System SELinux nutzt.Environment=setzt Umgebungsvariablen.[Service]enthält klassische systemd-Service-Optionen.Restart=on-failuresorgt für den Neustart nach einem Absturz – das Pendant zur Compose-Restart-Policy.[Install]mitWantedBy=default.targetverankert den Dienst so, dass er beim Hochfahren der User-Session mitstartet.
Der Ablauf im Ueberblick:
web.container (~/.config/containers/systemd/)
|
| systemctl --user daemon-reload
v
+---------------------+
| Quadlet-Generator | erzeugt Unit zur Laufzeit
+----------+----------+
|
v
web.service (transient)
|
| systemctl --user start web.service
v
+---------------------+
| rootless Container | caddy:2 -> Host :8080
+---------------------+
Autostart ohne aktives Login
WantedBy=default.target allein genügt nicht, wenn niemand eingeloggt ist: Der User-Manager läuft standardmäßig nur, solange eine Session offen ist. Damit Ihr Dienst nach einem Reboot auch ohne Login startet, aktivieren Sie Linger für Ihren Benutzer:
loginctl enable-linger
Ab jetzt startet systemd Ihren User-Manager beim Boot und hält ihn nach dem Logout am Leben – der Container läuft dauerhaft.
Drei typische Stolperfallen
1. Servicename ist der Dateiname, nicht der Container-Name. Aus web.container wird web.service. Sie steuern den Dienst also mit systemctl --user start web.service – nicht über einen im Container gesetzten Namen. Verwechslungen führen zu „Unit not found“.
2. Kein systemctl enable für Quadlet-Dienste. Die generierten Units sind aus Sicht von systemd transient und lassen sich nicht mit systemctl enable für den Boot verankern. Der Autostart wird ausschließlich über [Install] WantedBy= in der .container-Datei plus daemon-reload gesteuert. Ein enable-Versuch schlägt fehl.
3. Ports unter 1024 gehen rootless nicht ohne Weiteres. Als normaler Benutzer dürfen Sie privilegierte Ports (< 1024) standardmäßig nicht binden. Deshalb PublishPort=8080:80 statt 80:80. Wollen Sie den Dienst nach außen auf Port 80/443 anbieten, setzen Sie einen Reverse Proxy davor oder passen net.ipv4.ip_unprivileged_port_start an – für den Einstieg bleiben Sie bei einem hohen Host-Port.
Wie es weitergeht
Damit steht ein sauberes, rootless Muster, das sich auf jeden weiteren Dienst überträgt: .container-Datei, daemon-reload, --user start, enable-linger. Naheliegende nächste Schritte sind eigene Netzwerke (.network) und Volumes (.volume) als weitere Quadlet-Dateien sowie das Zusammenfassen mehrerer Container in einem Pod (.pod). Die Details stehen in der offiziellen Dokumentation: podman-systemd.unit (Quadlet) und die Podman-Dokumentation.
Hinweis: Die Beiträge dieses Blogs werden unter Einsatz von KI erstellt und vor der Veröffentlichung redaktionell geprüft. Die redaktionelle Verantwortung trägt Emre Yurtbay (siehe Impressum).