Solving a common “permission denied” error in rootless podman

Podman is different from docker in that it typically runs its containers rootless. Just as any other process without root privileges this has certain implications, this blog covers a common one. This article by RedHat covers a lot more ground should you not find the solution for your issue here.

Assume for example that you want to mount a local directory (data) into a container instance such as Gerald Venzl’s Oracle Free to store your database. Other use cases include the use of bootstrap scripts, etc. If you try the approach that works for the default docker setup, you get an error in podman:

$ mkdir -v ./data
$ podman run --rm -it --name oracle \
--volume ./data:/opt/oracle/oradata \
--environment ORACLE_PASSWORD=changeOnInstall \
docker.io/gvenzl/oracle-free:23.26.3
CONTAINER: starting up...
CONTAINER: first database startup, initializing...
CONTAINER: uncompressing database data files, please wait...
ERROR: Cannot create folder : errno=13 : Permission denied : /opt/oracle/oradata/FREE
ERROR: Cannot create folder : errno=2 : No such file or directory : /opt/oracle/oradata/FREE/FREEPDB1
ERROR: Cannot create folder : errno=2 : No such file or directory : /opt/oracle/oradata/FREE/pdbseed
ERROR: Cannot open output file : errno=2 : No such file or directory : /opt/oracle/oradata/FREE/FREEPDB1/sysaux01.dbf
ERROR: Cannot open output file : errno=2 : No such file or directory : /opt/oracle/oradata/FREE/FREEPDB1/system01.dbf
[more errors]

The problem occurs in line 9: the entrypoint script fails in creating the directory storing the database with errno = 13: permission denied. Subsequent errors (errno = 2) occur as a consequence of the missing directory.

And yes, you can run docker in rootless mode, too, although it requires a separate rootless setup.

But why does this happen?

Rather than letting the container start the database creation, let’s change the entrypoint to look at the directory permissions:

$ podman run --rm -it --entrypoint bash \
--volume ./data:/opt/oracle/oradata \
docker.io/gvenzl/oracle-free:23.26.3
bash-4.4$ ls -ld /opt/oracle/oradata
drwxrwxr-x 2 root root 4096 Sep 1 08:06 /opt/oracle/oradata

Looking at these directory permissions it quickly becomes clear why the entrypoint script fails to extract the files. The oracle user cannot write to this directory. According to the aforementioned RedHat article, this is a namespace problem. On a system where SELinux is enabled and enforcing, its security policy may impose an additional restriction on the bind mount.

Correcting the bind mount

One way to make the directory writable for oracle is to mount it with the U option. On an SELinux-enforcing host, add Z as well:

$ podman run --rm -it --entrypoint bash \
--volume ./data:/opt/oracle/oradata:Z,U \
docker.io/gvenzl/oracle-free:23.26.3
bash-4.4$ ls -ld /opt/oracle/oradata
drwxrwxr-x 2 oracle oinstall 4096 Sep 1 08:06 /opt/oracle/oradata

These two options solve different problems:

  • U recursively changes the host ownership of the bind-mounted directory to the host UID and GID that correspond to the container user.
  • Z gives the directory a private container label on an SELinux-enabled host. Use lowercase z instead when multiple containers need to share the content.

The ownership problem is addressed by U; Z addresses the separate SELinux restriction that may apply on your host.

Warning: U recursively changes the ownership of the host directory and everything already inside it. Do not apply it casually to a shared or valuable directory. Both U and Z walk the directory tree, so they can also delay container startup when it contains many files.

With the ownership corrected, and the SELinux label corrected if applicable, the database can initialize successfully:

$ podman run --rm -it --name oracle \
--volume ./data:/opt/oracle/oradata:Z,U \
--environment ORACLE_PASSWORD=changeOnInstall\
docker.io/gvenzl/oracle-free:23.26.3
CONTAINER: starting up...
CONTAINER: first database startup, initializing...
CONTAINER: uncompressing database data files, please wait...
CONTAINER: done uncompressing database data files, duration: 3 seconds.
CONTAINER: starting up Oracle Database...
LSNRCTL for Linux: Version 23.26.3.0.0 - Production on 01-SEP-2026 08:22:32
Copyright (c) 1991, 2026, Oracle. All rights reserved.
Starting /opt/oracle/product/26ai/dbhomeFree/bin/tnslsnr: please wait...
TNSLSNR for Linux: Version 23.26.3.0.0 - Production

No more permission errors!

Summary

Namespace problems are notorious when mounting directories from your development laptop into a running container instance. With the simple :Z,U fix, they should be a thing of the past unless your security team forbids them as they don’t come without side effects. Refer to podman run documentation for details.

Nearby: if direct host access is unnecessary, a Podman-managed named volume should be used instead. The explicit podman volume create command is optional: Podman creates the named volume automatically if it does not already exist.

$ podman volume create oracle-data
$ podman run --rm -it --name oracle \
--volume oracle-data:/opt/oracle/oradata \
--environment ORACLE_PASSWORD=changeOnInstall \
docker.io/gvenzl/oracle-free:23.26.3

Have fun!