Skip to main content
On this page

Quadlet reference

These unit files are generated per container:

FilePath (5.6–5.x)Path (6.0+)Purpose
<name>.build~/.config/containers/systemd/~/.config/containers/systemd/<name>/Image build definition
<name>.container~/.config/containers/systemd/~/.config/containers/systemd/<name>/Container runtime
<name>.socket~/.config/systemd/user/~/.config/systemd/user/Host-guest Unix socket (custom)
<name>-host.service~/.config/systemd/user/~/.config/systemd/user/Host socket server (custom)
<name>-proxy.service~/.config/systemd/user/~/.config/systemd/user/D-Bus proxy (conditional, custom)
<name>-compositor.service~/.config/systemd/user/~/.config/systemd/user/Wayland firewall proxy (conditional, custom)
<name>-x11.service~/.config/systemd/user/~/.config/systemd/user/Per-container X11 bridge (conditional, custom)

.build file

KeyValueNotes
ImageTaglocalhost/podbox-<name>:latestLocal tag for built image
FileAbsolute path to ContainerfileMust be absolute
RetryFrom image.pull_retryPull retry count (default 3)
RetryDelayFrom image.pull_retry_delayPull retry delay (default 5s)

.socket file

KeyValueNotes
ListenStream%t/podbox/<name>.sock%t = $XDG_RUNTIME_DIR
Service<name>-host.serviceActivates the host socket server
SocketMode0600User-only access
DirectoryMode0700Parent dir permissions

.container file

[Unit]

KeyValueNotes
Descriptionpodbox -- <name>Human-readable name
Requires<name>.socketSocket must be available
After<name>.socketSocket starts first
Requires<name>-proxy.serviceD-Bus proxy (conditional on [dbus] rules)
After<name>-proxy.serviceProxy starts first (conditional)
Requires<name>-compositor.serviceWayland firewall (conditional on Wayland proxy)
After<name>-compositor.serviceCompositor starts first (conditional)
Wants<name>-x11.serviceOptional X11 bridge (conditional on integration.x11)
After<name>-x11.serviceX11 bridge is started before the container (conditional)
RequiresUser-defined from [systemd].requiresCustom dependencies
AfterUser-defined from [systemd].afterCustom ordering
StartLimitBurst5Max restarts in interval
StartLimitIntervalSec30sRestart burst window

[Container]

KeyValueNotes
ImagePrebuilt ref or localhost/podbox-<name>:latestPrebuilt images use the registry ref directly; custom builds use local tag
RetryFrom image.pull_retryPull retries (prebuilt only)
RetryDelayFrom image.pull_retry_delayPull retry delay (prebuilt only)
ContainerName<name>Podman container name
UserNSkeep-id (default)User namespace mode (configurable via security.userns: keep-id, nomap, private)
UserrootRun as root inside the container (UID mapped via UserNS)
SecurityLabelDisabletrueRequired for Wayland socket access
SeccompProfileFrom security.seccompSeccomp profile (conditional, e.g. "default", "unconfined")
NoNewPrivilegestrueEmitted when security.no_new_privileges = true (default). Set false to allow sudo, su, AUR helpers.
MemoryFrom container.memoryMemory limit (conditional, e.g. "4G")
PodmanArgs=--cpus=From container.cpusCPU limit (conditional, e.g. "0.5" → --cpus=0.5; Quadlet has no CpuQuota key)
ReadOnlytrueRead-only rootfs (conditional on security.read_only_rootfs)
RunInittrueAlways (catatonit as PID 1 for zombie reaping)
WorkingDir/home/%uAlways (default working directory)
AddCapabilityFrom security.cap_preset + security.cap_addCapabilities (conditional; Quadlet has no CpuQuota key, so --cpus still goes through PodmanArgs)
AppArmorFrom security.apparmorAppArmor profile (conditional, e.g. "unconfined")
AddDevice/dev/driGPU (conditional on gpu=true or gpu="auto" with DRI present)
AddDevicenvidia.com/gpu=all when a host CDI spec exists, else -/dev/nvidiactl, -/dev/nvidia0…-/dev/nvidia7, -/dev/nvidia-modeset, -/dev/nvidia-uvm, -/dev/nvidia-uvm-toolsNVIDIA GPU passthrough (conditional on gpu="nvidia" or gpu="auto" with NVIDIA present; - marks each fallback node optional, and doctor suggests nvidia-ctk cdi generate for full driver passthrough)
NetworkFrom network.modeNetwork mode (default host)
PublishPortFrom network.portsPort mapping (conditional, ignored in host mode)
AutoUpdateregistry or localAuto-update (conditional on lifecycle.auto_update; registry for prebuilt, local for custom)
ReloadCmdFrom container.reload_cmdReload command (conditional)
TimezonelocalTimezone sync (conditional on host /etc/localtime; replaces the old bind-mount so zone-name lookups keep working)

Environment= entries

VariableSourceNotes
HOME/home/%uAlways set
HOST_USERHost usernameInjected into container
HOST_UID%U (systemd)Host UID
HOST_GID%G (systemd)Host GID
PATH/run/podbox/bin:...Interceptor directory prepended
WAYLAND_DISPLAYFrom host envWayland display (conditional)
DISPLAY:0X11 display (conditional on integration.x11; explicit [container.env] DISPLAY wins)
XDG_RUNTIME_DIR%tAlways set when Wayland is enabled
MOZ_ENABLE_WAYLAND1Wayland-native Firefox/Thunderbird (conditional)
PIPEWIRE_RUNTIME_DIR%tPipeWire runtime dir (conditional)
PULSE_SERVERunix:%t/pulse/nativePulseAudio server (conditional)
DBUS_SESSION_BUS_ADDRESSProxy or directD-Bus address (conditional)
SSH_AUTH_SOCK/run/podbox/ssh-agent.sockSSH agent (conditional, Podman ≥ 5.6)
GPG_TTY/dev/pts/0GPG TTY (conditional)
GNUPGHOME/run/podbox/gnupgGPG home (conditional)
LANGFrom host localeLocale (conditional; LC_* overrides stay with the user)
PODBOX_CONTAINER<name>Always set; identifies the container

Custom [container.env] entries are also passed as Environment=.

Volume= entries

SourceDestinationModeCondition
<context>/.flatpak-info/.flatpak-inforoAlways (sandbox detection — tricks apps into using portals)
%h/containers/<name>/home/%uZAlways (isolated home)
XDG dirs/home/%u/<dir>ro,z or zPer [integration.xdg_dirs]
%h/.themes/home/%u/.themesrosync_themes + path exists
%h/.local/share/themes/home/%u/.local/share/themesrosync_themes + path exists
%h/.icons/home/%u/.iconsrosync_icons + path exists
%h/.local/share/icons/home/%u/.local/share/iconsrosync_icons + path exists
%h/.fonts/home/%u/.fontsrosync_fonts + path exists
%h/.local/share/fonts/home/%u/.local/share/fontsrosync_fonts + path exists
/etc/timezone/etc/timezoneroFile exists on host (Debian convention; /etc/localtime itself is set up via Timezone=local, not a bind-mount)
Wayland socketWayland socketrowayland = true
%t/pipewire-0%t/pipewire-0(none)audio = true + PipeWire present
%t/pulse%t/pulse(none)audio = true + PulseAudio present
D-Bus socketD-Bus socket(none)dbus = true
SSH agent socket/run/podbox/ssh-agent.sock(none)ssh_agent = true + SSH_AUTH_SOCK present on host (plus Environment=SSH_AUTH_SOCK)
GPG agent socket/run/podbox/gnupg/S.gpg-agentrogpg_agent = true
%t/podbox/<name>.sock%t/podbox/<name>.sock(none)Always (host-guest socket)
/dev/bus/usb/dev/bus/usb(none, never :z)integration.hardware.usb = true (optional mount: skipped when the host has no USB bus)
Extra mountsPer configPer configFrom [container.mounts].extra
%t/podbox/<name>-x11/tmp/.X11-unixrointegration.x11 = true

PodmanArgs=

Only settings with no native Quadlet key go through PodmanArgs=:

ArgNotes
--cpus=<n>From container.cpus (conditional; Quadlet has no CpuQuota key, and --cpus also takes fractions like 0.5)

[Service]

KeyValueNotes
Restarton-failureAuto-restart on crash
RestartSec2sDelay between restarts

Quadlet runs containers with --rm --replace, so every box is ephemeral: stopping one removes it, and persistent state lives in the home volume and snapshots. (lifecycle.on_stop is deprecated and emits nothing.)

[Install]

KeyValueNotes
WantedBydefault.targetOnly when lifecycle.autostart = true

Companion .service files

<name>-host.service

Generated at ~/.config/containers/systemd/<name>-host.service:

ini
1[Unit]
2Description=podbox host socket server -- <name>
3 
4[Service]
5Type=simple
6ExecStart=<podbox> serve <name>
7Restart=on-failure
8RestartSec=2s
9RuntimeDirectory=podbox
10 
11[Install]
12WantedBy=<name>.socket

<name>-proxy.service (D-Bus proxy)

Generated when [dbus] talk/own rules are configured. See dbus-proxy.md for details.

<name>-compositor.service (Wayland firewall)

Generated when wayland.firewall = true (default). Runs podbox compositor <name> to filter Wayland protocol access.

<name>-x11.service (xwayland-satellite)

Generated when integration.x11 = true. The host-side satellite connects to the same filtered or direct Wayland socket used by the container and exposes an isolated :0 X socket directory:

ini
1[Unit]
2Wants=<name>-x11.service
3After=<name>-x11.service
4 
5[Service]
6Type=notify
7ExecStart=<xwayland-satellite> :0
8Environment=WAYLAND_DISPLAY=<derived Wayland socket>
9PrivateTmp=yes
10PrivateNetwork=yes
11BindPaths=%t/podbox/<name>-x11:/tmp/.X11-unix

The companion unit is optional at runtime: the container can start if the satellite is unavailable, but X11 applications will not work.

Podman Version Targeting

Podbox targets Podman 5.5+ with feature gating at 5.6 and 6.0.

FeaturePodman 5.5.xPodman ≥ 5.6, < 6.0Podman ≥ 6.0
ssh_agentVolume= + Environment=SSH_AUTH_SOCK on all versionsVolume= + Environment=SSH_AUTH_SOCK on all versionsVolume= + Environment=SSH_AUTH_SOCK on all versions
Quadlet installManual copy into ~/.config/containers/systemd/podman quadlet install --replace with file args (flat layout)podman quadlet install --replace --application <name> <dir> (app-subdir layout)
Quadlet uninstallManual file remove + systemctl daemon-reloadpodman quadlet rm <name>.container (flat)podman quadlet rm --recursive <name> (app-subdir) + flat fallback
Container listpodman ps --filter label=podbox.*podman quadlet listpodman quadlet list

Layout by version:

  • 5.6–5.x: Units at …/systemd/<name>.container (flat).
  • 6.0+: Units at …/systemd/<name>/<name>.container (app-subdir via --application).

Status, doctor, and start probes check both layouts, so upgrades between versions are transparent.

See podbox doctor to check Podman version compatibility.

Important Notes

  • %t is the systemd specifier for $XDG_RUNTIME_DIR — never substitute it.
  • %h is the systemd specifier for the user's home — never substitute it.
  • %U / %G expand to the user's UID and GID at unit start time.
  • Quadlet files (.container, .build) go in ~/.config/containers/systemd/.
    • Podman 5.6–5.x: flat layout (<name>.container).
    • Podman 6.0+: app-subdir layout (<name>/<name>.container).
  • Custom systemd units (.socket, -host.service, etc.) always go in ~/.config/systemd/user/.
  • Re-running podbox enable is safe — it uses --replace to overwrite existing Quadlet files idempotently.