Rootless Podman Defaults
You are root inside the container and uid 1000 outside it, at the same instant, for the same process. A file the container creates as root lands in your home directory owned by you - and `sudo podman images` is empty.
Foundations Guide 3 of 47 Intermediate
- OSUbuntu 26.04 LTS (resolute)
- Podman5.7.0
- Runtimecrun 1.21
- Networknetavark 1.16.1
- TimeAbout 15 min
- Reviewed22 August 2026
Written against the versions above. Podman follows the distribution here rather than a vendor repository, so the version you get is the one Ubuntu shipped. The commands are stable across 5.x.
| Server Name | IP Address | OS | Roles | CPU | RAM | HDD |
|---|---|---|---|---|---|---|
| PODMAN01 | 192.168.0.24 | Ubuntu 26.04 LTS | Primary Container Host | 2 Core | 4 GB | 50 GB |
Before you start
- Podman installed - see guide 1.
- A subordinate UID range for your user.
cat /etc/subuidmust name you; Ubuntu'suseraddallocates one automatically.
-
Two answers to the same question
Ask who you are on the host, then ask the same thing inside a container.
You get
uid=1000(sysadmin)anduid=0(root). Both are true. Neither is a trick and nothing was escalated -sudowas not used and no setuid binary ran your container.bash Example session iduid=1000(sysadmin) gid=1000(sysadmin) groups=1000(sysadmin),4(adm),24(cdrom),27(sudo),30(dip),46(plugdev),100(users),101(lxd)podman run --rm docker.io/library/alpine iduid=0(root) gid=0(root) groups=0(root),1(bin),2(daemon),3(sys),4(adm),6(disk),10(wheel),11(floppy),20(dialout),26(tape),27(video)Expected result
uid=1000(sysadmin)on the host,uid=0(root)inside the container.Success conditionYou have the host's answer written down before the container contradicts it.
-
The mapping that makes both true
/proc/self/uid_mapis where the contradiction resolves. On the host it is the trivial identity map - every UID is itself:0 0 4294967295Inside the container it is two lines, and they are the entire rootless model:
0 1000 1 1 100000 65536Read each as inside, outside, count:
- Container UID
0is host UID1000, for1UID. Root in this container is you. - Container UIDs
1through65536are host UIDs100000upward. Those are the subordinate UIDs from/etc/subuid, which the kernel let you claim because an administrator allocated them to you in advance.
So the container's root has exactly your privileges, and its other users have the privileges of accounts that do not otherwise exist. There is no path from
uid 0in here touid 0out there, because no line in the map points at it.bash Example session cat /proc/self/uid_map 0 0 4294967295podman run --rm docker.io/library/alpine cat /proc/self/uid_map 0 1000 1 1 100000 65536Expected resultThe identity map on the host, and a two-line map inside the container.
Success conditionYou can read a uid_map line as inside, outside, count.
- Container UID
-
One process, two identities
The mapping is not a label on a container - it applies to the running process, and you can see both views of the same PID.
podman toplooks from inside: the process isroot, PID1.pson the host looks from outside: the same process issysadmin. Nothing translated the answer; the kernel genuinely reports a different UID depending on which namespace is asking.The stop is worth a glance too.
sleepdoes not handleSIGTERMwhen it is PID 1, so Podman waits ten seconds and then sendsSIGKILL. That is its own guide later in the path - it is not a Podman quirk, it is what PID 1 means.bash Example session podman run -d --name sleeper docker.io/library/alpine sleep 3001c580317306e487ec11dce24ca3eae5abd0d26d3065f13e6aa2660ca09cc82a3podman top sleeper user pidUSER PIDroot 1ps -o pid,user,comm -p $(podman inspect -f '{{.State.Pid}}' sleeper) PID USER COMMAND 8037 sysadmin sleeppodman stop sleepertime="2026-08-22T10:56:14Z" level=warning msg="StopSignal SIGTERM failed to stop container sleeper in 10 seconds, resorting to SIGKILL"sleeperpodman rm sleepersleeperExpected result
root 1from inside, and the same process owned bysysadminoutside.Success conditionYou have looked at one process from both sides of the namespace.
-
The file test
This is the one to remember, because it is where rootless stops being trivia and starts costing you an afternoon.
Bind mount a directory from your home, and have the container's root create a file in it. From inside,
ls -lnreports owner0. From outside, the same file reports owner1000.Nothing changed the file.
0inside is1000outside, so both listings are reporting the same number through different maps.The corollary is what bites people: a container process running as any user other than root writes files owned by a host UID in the 100000 range, which your account cannot delete without help. That failure, and the
--userns=keep-idflag that avoids it, is the subject of the Storage track.bash Example session mkdir -p ~/sharedpodman run --rm -v ~/shared:/data docker.io/library/alpine sh -c 'touch /data/made-by-root && ls -ln /data'total 0-rw-r--r-- 1 0 0 0 Aug 22 10:56 made-by-rootls -ln ~/sharedtotal 0-rw-r--r-- 1 1000 1000 0 Aug 22 10:56 made-by-rootExpected resultOwner
0inside the container, owner1000outside, for one file.Success conditionYou have produced the same file with two different owners and can say why.
-
Rootful is a different machine
Rootless and rootful Podman are not two modes of one installation. They are two separate stores, two separate sets of containers, and two separate networks that happen to share a binary.
podman inforeports a graphroot under your home.sudo podman inforeports/var/lib/containers/storageandrootless=false.The proof is the image list. You pulled three images in the last two guides.
sudo podman imagesshows none of them - not because permission was denied, but because root has never pulled anything and is looking in a different directory.Practical consequence:
sudois not a way to fix a Podman problem. It is a way to get a different, empty Podman. If a command fails withoutsudo, adding it will usually make the error go away by making the whole context go away.bash Example session podman info --format 'graphroot={{.Store.GraphRoot}} rootless={{.Host.Security.Rootless}}'graphroot=/home/sysadmin/.local/share/containers/storage rootless=truesudo -n podman info --format 'graphroot={{.Store.GraphRoot}} rootless={{.Host.Security.Rootless}}'graphroot=/var/lib/containers/storage rootless=falsepodman imagesREPOSITORY TAG IMAGE ID CREATED SIZEdocker.io/library/nginx alpine 7bc5ba2f958a 2 days ago 64.2 MBdocker.io/library/alpine latest d529dd0c6e55 2 months ago 8.71 MBdocker.io/library/hello-world latest e2ac70e7319a 5 months ago 25.5 kBsudo -n podman imagesREPOSITORY TAG IMAGE ID CREATED SIZEExpected resultTwo different graphroots,
rootless=truethenfalse, and an empty image list for root.Success conditionYou can explain why
sudo podman imagesis empty on a machine full of images.
Troubleshooting
Error: cannot set up namespace using "/usr/bin/newuidmap": exit status 1.Why: No subordinate UID range, or
newuidmaphas lost its file capability.Fix:Check
/etc/subuidand/etc/subgidname your user, thengetcap /usr/bin/newuidmap- it should reportcap_setuid=ep. Reinstalluidmapif it does not.After changing
/etc/subuid, containers still fail the same way.Why: Podman caches the mapping in its store, so an existing store keeps the old range.
Fix:
podman system migrate. It re-creates the user namespace configuration without removing images.Files written by the container are owned by a UID like
100999and you cannot delete them.Why: The container process was not root, so its UID mapped into your subordinate range rather than onto your own account.
Fix:
podman unshare rm -rf ./dirruns the removal inside the same user namespace, where those files are owned by root. Preventing it in the first place is--userns=keep-id, covered in the Storage track.sudo podmanandpodmandisagree about what containers exist.Why: Working as intended. They are separate stores.
Fix:Pick one and stay in it.
podman info --format '{{.Store.GraphRoot}}'tells you which one you are in.