Keeping Rootless Podman Containers Alive with systemd User Services
Rootless Podman containers die when your SSH session ends. Use generated systemd user units and linger to keep them running across reboots without a daemon.
13 Jun 2026, 19:49 UTC

Rootless Podman removes the always-on daemon, but it introduces a lifecycle problem: containers started from an interactive shell belong to that shell's systemd user session. When you log out, systemd tears down the session and your containers stop. If you want a local database or web service that survives disconnects and reboots, you need to hand ownership to the systemd user manager.
The fix is to generate a systemd unit from your container definition and enable linger so the user manager starts at boot. This gives you daemonless persistence without granting the container root privileges on the host.
Why rootless containers need subuid ranges
Podman runs rootless containers by creating a user namespace. Inside the container, processes appear to run as root, but on the host they are mapped to your unprivileged UID plus a range of subordinate IDs. The host kernel needs to know which UIDs and GIDs your user is allowed to claim; these ranges live in /etc/subuid and /etc/subgid.
Check that your user has an assigned range:
cat /etc/subuid /etc/subgid
You should see a line like alice:100000:65536. If the file is empty or your username is missing, rootless container creation fails because Podman cannot map the container root user to a host identity.
Confirm Podman is actually running rootless:
podman info --format '{{.Host.Security.Rootless}}'
Expected output is true.
Closing the persistence gap with linger
By default, systemd starts a user manager only when you log in and stops it when the last session ends. Enabling linger changes that: the manager starts at boot and keeps running until you explicitly disable it. This is what allows user services to outlive SSH sessions.
Enable linger (requires sudo on the host):
sudo loginctl enable-linger $USER
Verify the setting:
loginctl show-user $USER | grep Linger
Expected output is Linger=yes.
Worked example: a container as a boot-time service
Suppose you want a local Nginx instance listening on host port 8080. Start it once so Podman can capture the exact runtime arguments:
podman run -d --name web -p 8080:80 docker.io/library/nginx:stable
Generate a user-level systemd unit. The --new flag is important: it tells systemd to create a fresh container on each start rather than trying to restart a stale one.
mkdir -p ~/.config/systemd/user podman generate systemd --name web --new --file ~/.config/systemd/user/web.service
Stop the manually started container and let systemd take over:
podman stop web systemctl --user daemon-reload systemctl --user enable --now web.service
Check the service status:
systemctl --user status web.service
And confirm the application responds:
curl -I http://localhost:8080
You should see an HTTP 200 response. If the service fails, inspect the journal with journalctl --user -u web.service.
What rootless changes about networking and volumes
Rootless networking is not identical to rootful Podman. Most distributions use slirp4netns or pasta to provide network connectivity without host network namespace privileges. Recent kernels with unprivileged network namespace support can reduce this dependency, but the exact helper and behavior vary by Podman version and kernel release, so verify what your installation uses with podman info.
The most common surprise is port binding. Unprivileged users cannot bind to ports below 1024. If your service must listen on port 80 or 443, the container will fail to start. You have two options:
- Publish on a high port (e.g.,
-p 8080:80) and terminate TLS or reverse-proxy at a host-level service. - Lower the kernel threshold on the host (requires sudo and affects all users):
sudo sysctl -w net.ipv4.ip_unprivileged_port_start=80
Volume mounts are also more constrained. Rootless containers may reject certain filesystem types, and SELinux labels on host directories can block access. If a bind mount fails, check the container logs and confirm the host path is readable by your user.
Verification checklist
Before relying on this setup, run through these checks:
podman inforeportsrootless: true./etc/subuidand/etc/subgidcontain a range for your user.loginctl show-user $USERshowsLinger=yes.systemctl --user is-enabled web.servicereturnsenabled.- After a reboot,
podman psshows the container running.
This approach is not a substitute for a full container orchestrator, and it does not make rootless containers equivalent to rootful ones. It does, however, give you a lightweight, daemonless way to keep local services running across logout and reboot. Start by enabling linger and generating one unit; if the service survives a reboot and answers on its published port, the pattern is working.
0 replies
A thoughtful contribution can make all the difference. Be the first to share one.