Rootless podman on openSUSE with cgroup delegation

Give containers their own unprivileged user, make limits work with cgroup delegation, and avoid the session traps.

Part 7 of 10 in openSUSE home server setup. Last updated

In short: Install podman, create a normal user for your containers, check that it has ranges in /etc/subuid and /etc/subgid, and run sudo loginctl enable-linger for it so its services start at boot. Log in as that user over SSH (not with su) so systemctl --user works. For CPU and IO limits, delegate the controllers with a drop-in for user@.service containing Delegate=cpu cpuset io memory pids. Ports below 1024 need a sysctl change or a reverse proxy.

Why rootless?

A container escape from a rootful container lands as root on the host. From a rootless one it lands as an unprivileged user who owns nothing but its own containers. Rootless podman needs no daemon either: each container is a normal process tree of that user, started by systemd. Most home services (DNS filters, media apps, dashboards) run fine this way.

Root in the container is just you on the host; every other container user lands in your sub-UID range.

The same mapping as the kernel reports it, and a container's root process seen from the host:

$ grep "^$(id -un):" /etc/subuid /etc/subgid
/etc/subuid:user:100000:65536
/etc/subgid:user:100000:65536
$ podman unshare cat /proc/self/uid_map
         0       1000          1
         1     100000      65536

Real output on openSUSE Tumbleweed, podman 6.0.2, 2026-09-28; user and host names and addresses redacted.

$ podman run --rm registry.fedoraproject.org/fedora:latest sh -c 'id; sleep 30' &
uid=0(root) gid=0(root) groups=0(root)
$ podman top -l user huser pid hpid comm
USER        HUSER       PID         HPID        COMMAND
root        1000        1           3116953     sleep
$ podman run -d --rm --name demo-uid --user 1000:1000 registry.fedoraproject.org/fedora:latest sleep 60
$ podman top demo-uid user huser pid hpid comm
USER        HUSER       PID         HPID        COMMAND
user        100999      1           3119456     sleep

Real output on openSUSE Tumbleweed, podman 6.0.2, 2026-09-28; user and host names and addresses redacted.

Install podman and prepare a user

The commands with sudo need root:

sudo zypper install podman
podman --version                           # Tumbleweed: newest; Leap 16: 5.x
sudo useradd -m -s /bin/bash apps          # a normal user for your containers
sudo passwd apps                           # or copy an SSH key for it
grep apps /etc/subuid /etc/subgid          # apps:100000:65536 in both files
sudo loginctl enable-linger apps           # its services start at boot, survive logout

The sub-UID range is the pool of user IDs the user's containers map to. If grep finds nothing, add a range that does not overlap with other users:

sudo usermod --add-subuids 200000-265535 --add-subgids 200000-265535 apps
podman system migrate                      # as apps: pick up the new range

Log in the right way

Rootless podman and systemctl --user need a real login session with XDG_RUNTIME_DIR set. su - apps and sudo -u apps do not create one, and you get errors such as "Failed to connect to bus" or warnings about the runtime directory. Log in properly instead:

ssh apps@homeserver                        # simplest
sudo machinectl shell apps@                # from another admin account (systemd-container package)
systemctl --user status                    # works in both

Check that lingering is on for the container user, so its services start at boot:

$ loginctl show-user $(id -un) -p Linger
Linger=yes
$ podman info --format 'rootless={{.Host.Security.Rootless}} cgroups={{.Host.CgroupsVersion}} manager={{.Host.CgroupManager}}'
rootless=true cgroups=v2 manager=systemd

Real output on openSUSE Tumbleweed, podman 6.0.2, 2026-09-28; user and host names and addresses redacted.

cgroup v2 and delegation

Limits such as --memory or --cpus only work when systemd hands the matching cgroup controllers to the user. First check that the system runs cgroup v2, then see which controllers the user got:

stat -fc %T /sys/fs/cgroup                 # cgroup2fs = cgroup v2
cat "/sys/fs/cgroup/user.slice/user-$(id -u).slice/user@$(id -u).service/cgroup.controllers"
# e.g. "memory pids": cpu and io limits will not work yet

Depending on the systemd version, only memory and pids (and perhaps cpu) are delegated. To delegate the rest, add a drop-in for every user's service manager (needs root):

sudo mkdir -p /etc/systemd/system/user@.service.d
printf '[Service]\nDelegate=cpu cpuset io memory pids\n' | sudo tee /etc/systemd/system/user@.service.d/delegate.conf
sudo systemctl daemon-reload

The change applies when the user's service manager restarts: reboot, or stop all of the user's sessions and services and log in again. Run the cat above once more to confirm. The background is in the podman troubleshooting guide.

Ports below 1024

Unprivileged users may not bind ports below 1024, so a rootless DNS server on 53 or a web server on 80 fails with "permission denied". Two options:

  • Publish a high port (PublishPort=8080:80) and put a reverse proxy or a firewalld forward in front. Nothing system-wide changes.
  • Lower the limit for everyone (needs root), which lets any local user bind ports from 53 upwards:
echo 'net.ipv4.ip_unprivileged_port_start=53' | sudo tee /etc/sysctl.d/90-unprivileged-ports.conf
sudo sysctl --system

Remember the firewall as well: published rootless ports need a firewalld rule, as the firewalld basics guide explains.

The limit on a default install, readable without root:

$ cat /proc/sys/net/ipv4/ip_unprivileged_port_start
1024

Real output on openSUSE Tumbleweed, 2026-09-28; user and host names and addresses redacted.

Common mistakes

Mixing podman and sudo podman

They use different storage, different networks and different containers. sudo podman ps never shows the rootless containers of your user, and the other way round. Pick rootless, stay rootless.

Services stop when you log out

Lingering is off. loginctl show-user apps -p Linger should say Linger=yes; if not, run sudo loginctl enable-linger apps.

Permission denied on a bind-mounted folder

Inside the container, root is your user, but other UIDs map to the sub-UID range. A folder the container's app user must write needs podman unshare chown, or a UserNS=keep-id setup. On SELinux systems, also check the label: see the AppArmor and SELinux guide.

Have a docker run command from a project's README? The docker run to quadlet converter turns it into a rootless quadlet; the quadlet basics guide is next.

Frequently asked questions

Where does rootless podman store images and volumes?

In the user's home: ~/.local/share/containers/storage. That is inside /home, so it is not part of root snapshots and needs its own backup. sudo podman uses a completely separate store in /var/lib/containers.

Why does podman warn about cgroup v1?

Rootless resource limits need the unified cgroup v2 hierarchy. Leap 16 and Tumbleweed use it by default; stat -fc %T /sys/fs/cgroup prints cgroup2fs there. If it prints tmpfs you are on an old hybrid setup, such as an upgraded Leap 15 install.

Can rootless containers talk to each other?

Yes, on a user-defined network (podman network create, or a .network quadlet) or inside one pod. Containers of different users cannot share a network; that separation is one of the reasons to use rootless.