whoami quadlet
The hello world of quadlets: one tiny web server as a systemd user service.
- Standalone container
- Rootless: systemctl --user
- Tested with podman 5.0 and newer
Last updated
See where this fits on the homelab connections map, with every port it uses.
In short: Save the 14-line whoami.container below in ~/.config/containers/systemd/, run systemctl --user daemon-reload, then systemctl --user start whoami.service. curl http://localhost:8080 answers with the container's hostname, its IP addresses and your request headers. Use it to prove that podman, quadlet and systemd work together before you deploy anything real.
The quadlet files
Every quadlet file below passes podman's quadlet generator and
systemd-analyze verify on podman 5.0 and the current release. Personal values
are placeholders: replace example.com, /srv/... paths and the
time zone with your own.
whoami.container
Save as ~/.config/containers/systemd/whoami.container
[Unit]
Description=whoami test web server
[Container]
Image=docker.io/traefik/whoami:v1.12
ContainerName=whoami
AutoUpdate=registry
PublishPort=8080:80
[Service]
Restart=always
[Install]
WantedBy=default.target
Why is it built this way?
whoami is the smallest useful quadlet: one .container file and nothing else. It has
no .volume because the server keeps no data, and no .network because the
default network is enough for one container that only needs a published port.
Rootless. The file lives in ~/.config/containers/systemd/, so it
runs under your own user with systemctl --user. Nothing here needs root: port 8080
is above 1024, and inside the container the server may still listen on port 80.
Pinned tag with auto-updates. traefik/whoami:v1.12 is a tag that
follows the 1.12 patch releases. AutoUpdate=registry lets
podman auto-update pull those patches and restart the service, and podman
rolls back if the new image fails to start. Auto-updates only work with a fully qualified image
name such as docker.io/traefik/whoami.
Restart and boot. Restart=always restarts the container when it
exits, and WantedBy=default.target starts it with your user session, or at boot
once lingering is on. Quadlet also adds a wait for the network to be online, so you do not need
an After=network-online.target line. Every key is documented in
podman-systemd.unit(5).
A request to curl http://localhost:8080 answers like this (addresses replaced by examples):
Hostname: 3e37468f5a20
IP: 127.0.0.1
IP: ::1
RemoteAddr: 10.0.2.100:43038
GET / HTTP/1.1
Host: localhost:8080
User-Agent: curl/8.21.0
Accept: */* How do I start it?
Run these as your normal user, not as root. Quadlet reads ~/.config/containers/systemd/ for user services.
mkdir -p ~/.config/containers/systemd
# save whoami.container there, then:
systemctl --user daemon-reload
systemctl --user start whoami.service
curl http://localhost:8080
# keep user services running after you log out:
loginctl enable-linger "$USER"
Check the result with systemctl --user status and
the logs with journalctl --user -u followed by the
service name. To turn a docker-compose file of your own into files like these, use the
compose to quadlet converter.
Common mistakes
Failed to enable unit: Unit whoami.service is transient or generated
Quadlet units cannot be enabled with systemctl enable. The [Install] section of the .container file does that job: WantedBy=default.target makes the generator link the service into default.target on every daemon-reload, so it starts at boot.
Unit whoami.service not found after daemon-reload
The generator skipped the file: a typo in a key, a wrong section name, or the file is not in ~/.config/containers/systemd/. Run /usr/lib/systemd/system-generators/podman-system-generator --user --dryrun (or /usr/libexec/podman/quadlet --user --dryrun on some distributions) to see the error.
The container stops when I log out of SSH
User services only run while you have a session, unless lingering is on. Run loginctl enable-linger once for your user; the service then also starts at boot without a login.
Frequently asked questions
What is the smallest working podman quadlet?
A .container file with an Image= line in a [Container] section is enough for the generator. In practice add ContainerName=, PublishPort= for access, Restart=always under [Service] and WantedBy=default.target under [Install], as in the whoami.container on this page.
Why use traefik/whoami to test a podman setup?
The image is about 13 MB, needs no configuration or volume, and answers every HTTP request with its hostname, IP addresses and the request headers. That makes it ideal for checking a quadlet, a published port or the headers a reverse proxy passes on.
How do I see the logs of a quadlet container?
Quadlet containers log to the systemd journal. Run journalctl --user -u whoami.service for a rootless container, or add -f to follow new lines. podman logs whoami shows the same output.
How do I remove a quadlet service again?
Stop it with systemctl --user stop whoami.service, delete the .container file, and run systemctl --user daemon-reload. The generated unit disappears; remove the image with podman rmi if you no longer need it.