Rootless Podman on a Raspberry Pi – Solving the “Cannot Bind Mount /home/user/data” Permission Issue
The Raspberry Pi has become a favorite platform for home‑lab enthusiasts, and Podman’s rootless mode lets you run containers without granting the container process full system privileges.
On a Pi running Raspberry OS Bookworm (Debian 12), a common stumbling block is the error
Error: cannot bind mount /home/user/data: permission denied
when you try to persist data with -v /home/user/data:/data.
Below is a step‑by‑step guide that explains why the error happens, how to fix it, and what security trade‑offs you should be aware of.
Why Rootless Podman on Pi?
Rootless containers rely on user namespaces to map the container’s root to an unprivileged UID/GID on the host.
This mapping is transparent to the container, but it also means that the container cannot access host paths unless the host path is owned by the mapped UID/GID or the container is granted additional capabilities.
The Pi’s default user namespace configuration is intentionally conservative, which is why bind mounts to a user’s home directory often fail.
The Bind Mount Problem
When you run
podman run -d --name web -v /home/user/data:/data nginx
Podman tries to create a bind mount inside the container’s mount namespace.
If the container’s root UID (e.g., 1000) does not own /home/user/data, the kernel denies the mount with EACCES.
Even if the host path is world‑readable, the container’s root is still unprivileged, so the kernel refuses the mount unless the container is given the CAP_SYS_ADMIN capability or the path is owned by the mapped UID.
Prerequisites
- Raspberry OS Bookworm (Debian 12) with the latest kernel (5.15+).
- Podman 4.10+ (install via
sudo apt install podman). - A regular user (
user) who can runsudofor initial setup. systemdpresent (default on Raspberry OS).
Verify the Podman version:
podman version
and the kernel:
uname -r
Understanding Capabilities and AppArmor
Rootless Podman uses the kernel’s user namespace and the userns-remap mechanism.
The container’s root is mapped to a UID/GID pair that lives in /etc/subuid and /etc/subgid.
If the host path is not owned by that UID/GID, the kernel’s mount(2) call fails.
AppArmor (or SELinux on other distros) can also block bind mounts if the container’s profile does not allow mount operations.
On Raspberry OS, AppArmor is disabled by default, so the issue is almost always a UID/GID mismatch.
Fix 1 – Use --userns=keep-id and Disable Labeling
The simplest workaround is to keep the container’s UID/GID identical to the host user’s.
Add the --userns=keep-id flag and disable the default SELinux/AppArmor labeling:
podman run -d \
--name web \
--userns=keep-id \
--security-opt label=disable \
-v /home/user/data:/data \
nginx
--userns=keep-idtells Podman to map the container’s root to the host UID/GID.--security-opt label=disableturns off the defaultuserlabel that Podman applies.
This approach works well for personal projects but defeats the isolation that rootless mode provides.
Use it only if you trust the container image and the data directory.
Fix 2 – Adjust userns-remap and /etc/subuid / /etc/subgid
A more secure solution is to add the host path to the user’s sub‑UID/GID range.
- Edit
/etc/subuidand/etc/subgid:
sudo sh -c 'echo "user:100000:65536" >> /etc/subuid'
sudo sh -c 'echo "user:100000:65536" >> /etc/subgid'
- Change ownership of the host directory to the first UID in the range:
sudo chown 100000:100000 /home/user/data
- Run the container normally:
podman run -d --name web -v /home/user/data:/data nginx
Now the container’s root (mapped to 100000) owns the bind mount, so the kernel allows it.
This preserves the isolation benefits of rootless mode while giving the container access to the required data.
Fix 3 – Use podman run --privileged (Not Recommended)
You can bypass the UID/GID restriction by granting the container full capabilities:
podman run -d --name web --privileged -v /home/user/data:/data nginx
--privileged gives the container CAP_SYS_ADMIN, CAP_SYS_CHROOT, and many others.
While this solves the mount issue, it also removes almost all of the security benefits of running rootless.
I usually avoid this unless you’re testing a very small, isolated image.
The bind‑mount problem is a classic illustration of how user namespaces work.
If you’re running a production‑grade service on a Pi, the sub‑UID/GID trick (Fix 2) gives you the best mix of safety and convenience.
For quick demos or when you’re certain the image is trustworthy, keep-id (Fix 1) is fine.
And the privileged route? Only for when you really need to do something that the kernel would otherwise block.
- raspberry-pi
- rootless
- containers
See also
- Finding the Most Frequent Syslog Lines in /var/log/syslog with awk, sort, and head
- Preventing Disk Space Woes on a Home NAS by Configuring Logrotate for Docker Container Logs
- Keep a 1 GB VPS from dying: a single cron job that purges /var/log/syslog after 30 days
- When firewalld blocks HTTP traffic even though port 80 is open: the services vs ports trap
- Stuck in emergency mode after adding an NTFS mount to /etc/fstab: how to fix it