Quadlet — cheat sheet
A one-page lookup for the commands and directives used across this course. Grouped by task; the course
pages cover the why behind each one — this page is just the what.
Locations & regenerate
| Task |
Command |
| Rootful Quadlet sources |
/etc/containers/systemd/ |
| Rootless Quadlet sources |
~/.config/containers/systemd/ |
| Generated units (never edit) |
/run/systemd/generator/ |
| Regenerate after editing (rootful / rootless) |
sudo systemctl daemon-reload / systemctl --user daemon-reload |
| Preview what a reload would generate |
sudo /usr/libexec/podman/quadlet -dryrun / -dryrun -user |
| See the actually-loaded generated unit |
systemctl cat <unit>.service |
.container — the most-used [Container] directives
| Directive |
Maps to |
Image= |
The image to run |
Exec= |
Command after the image, overrides the image CMD |
ContainerName= |
--name (default systemd-<unit-basename>) |
Volume= (repeatable) |
-v; :Z for a private SELinux label, :z for shared |
Network= (repeatable) |
--network; reference a .network file by basename + .network |
Pod= |
--pod; reference a .pod file by basename + .pod |
PublishPort= (repeatable) |
-p host:container[/proto] |
Environment= (repeatable) |
-e KEY=value |
EnvironmentFile= |
--env-file <path> |
User= / UserNS= |
--user uid[:gid] / --userns (auto, keep-id, nomap, host) |
ReadOnly=true / NoNewPrivileges=true |
--read-only / --security-opt=no-new-privileges |
DropCapability=ALL / AddCapability=... |
--cap-drop=ALL / --cap-add=... (repeat to stack) |
HealthCmd= / HealthInterval=30s |
--health-cmd / --health-interval |
AutoUpdate=registry |
--label io.containers.autoupdate=registry |
Pull=always |
--pull=always on start (default missing) |
PodmanArgs=... |
Escape hatch — appended verbatim to the generated podman run; use only when no directive fits |
.volume / .network / .pod — skeleton + reference
| Task |
How |
| Declare a named volume |
[Volume] section in <name>.volume; optional VolumeName=, Driver=, Label= |
| Reference it from a container |
Volume=<name>.volume:/path:Z in [Container] |
| Declare a named network |
[Network] section in <name>.network; optional Subnet=, Gateway=, Internal=true |
| Reference it from a container |
Network=<name>.network in [Container] |
| Use the host network instead (no isolation) |
Network=host directly in [Container], no .network file |
| Declare a pod |
[Pod] section in <name>.pod; PodName=, PublishPort=, Network= live here |
| Join a container to a pod |
Pod=<name>.pod in [Container]; drop that container's own Network=/PublishPort= |
| Stop every member of a pod together |
systemctl stop <name>-pod.service |
Check a .volume/.network unit's health |
systemctl status <name>-volume.service — a healthy one reports exited, not running |
Generated service names — the one irregular mapping
| Source suffix |
Generated service |
.container |
<basename>.service (no suffix added) |
.volume |
<basename>-volume.service |
.network |
<basename>-network.service |
.pod |
<basename>-pod.service |
.kube / .image / .build
| Task |
How |
| Run existing Kubernetes YAML |
.kube file with [Kube] → Yaml=<file>.yaml (relative to the .kube file) |
Start / stop a .kube deployment |
systemctl start <name>-kube.service runs podman play kube; stop runs podman play kube --down |
| Guarantee an image is pulled before use |
.image file with [Image] → Image=<ref>, optional AuthFile= |
Build an image from a local Containerfile at boot |
.build file with [Build] → ImageTag=, File=, WorkingDirectory=, BuildArg= |
Lifecycle & logs
| Task |
Command |
| Start / stop / restart / enable now |
sudo systemctl start\|stop\|restart <unit>.service / enable --now <unit>.service |
| Same, rootless |
systemctl --user start\|stop\|restart\|enable --now <unit>.service |
| Status |
systemctl status <unit>.service |
| Follow logs / since a time / errors only |
journalctl -u <unit>.service -f / --since "1 hour ago" / -p err |
| Rootless logs |
journalctl --user -u <unit>.service -f |
| Cross-check on the Podman side |
podman ps / podman inspect systemd-<name> / podman logs systemd-<name> |
Auto-update
| Task |
Command |
| Label a container for registry-driven updates |
AutoUpdate=registry in [Container] |
Label for local-image-driven updates (.build-managed images) |
AutoUpdate=local in [Container] |
| Enable the nightly timer, rootful / rootless |
sudo systemctl enable --now podman-auto-update.timer / systemctl --user enable --now ... |
| See the next scheduled run |
systemctl list-timers podman-auto-update.timer |
| Dry-run one cycle / force one now |
sudo podman auto-update --dry-run / sudo podman auto-update |
Rootless persistence
| Task |
Command |
| Keep a rootless user's systemd instance (and its timers) alive after logout |
loginctl enable-linger <user> |
| Confirm linger is set |
loginctl show-user <user> --property=Linger |
Allow a rootless container to bind a port <1024 |
echo 'net.ipv4.ip_unprivileged_port_start=80' \| sudo tee /etc/sysctl.d/80-rootless.conf && sudo sysctl --system |
How this connects
The .container anatomy page covers the pass-through/translate/merge split behind the directive table
above, the pods/networks/volumes page covers the one-shot-vs-running distinction and the dependency graph
Quadlet writes for you, and the auto-update page covers the full four-step cycle and the registry vs
local decision.