Podman is Red Hat’s recommended Docker-compatible container engine that runs containers without requiring a root-owned daemon. Unlike Docker, which requires the Docker daemon (dockerd) running as root, Podman runs containers directly as the user executing the command — a model called rootless containers. This eliminates an entire class of privilege escalation vulnerabilities: even if a container is compromised, the attacker cannot escalate to host root because the container runs under a regular user’s UID. Podman is fully integrated with RHEL 9 and SELinux, provides a Docker-compatible CLI (most docker commands work identically with podman), and supports running containers as systemd services. This guide covers installing Podman, running rootless containers, and using Podman as a drop-in Docker replacement on RHEL 9.
Prerequisites
- RHEL 9 with sudo/root access (rootless containers run as regular users)
Step 1 — Install Podman
# Podman is available in RHEL 9 AppStream
dnf install -y podman podman-compose
podman --version
podman-compose --version
Step 2 — Run Rootless Containers (as a Non-Root User)
# Switch to a regular user
su - myuser
# No sudo required for Podman!
podman run hello-world
# Run Nginx rootlessly
podman run -d --name webserver -p 8080:80 nginx:alpine
curl http://localhost:8080
# Rootless containers can only bind ports > 1024
# To bind port 80, either:
# - Use systemd socket activation with port forwarding
# - Or: sysctl -w net.ipv4.ip_unprivileged_port_start=80
Step 3 — Docker-Compatible Commands
# Create a Docker alias for teams transitioning from Docker
echo 'alias docker=podman' >> ~/.bashrc
source ~/.bashrc
# Podman uses the same syntax as Docker:
podman ps # = docker ps
podman images # = docker images
podman pull nginx # = docker pull nginx
podman build -t myapp . # = docker build -t myapp .
podman push myapp # = docker push myapp
podman exec -it myapp bash # = docker exec -it myapp bash
Step 4 — Auto-Start Containers with systemd
# Generate a systemd unit file for a running Podman container
podman run -d --name myapp myapp:latest
podman generate systemd --name myapp --new --files
# Install the generated service for the current user
mkdir -p ~/.config/systemd/user
cp container-myapp.service ~/.config/systemd/user/
systemctl --user enable --now container-myapp
# Enable auto-start on user login (without requiring a login session)
loginctl enable-linger $USER
Step 5 — Podman SELinux Integration
# Podman is SELinux-aware — label volumes correctly
podman run -d
--name webapp
-v /var/www/html:/usr/share/nginx/html:z # :z = shared label for multiple containers
-v /var/data:/data:Z # :Z = private label for single container
nginx:alpine
# :z applies the svirt_sandbox_file_t context (allows multiple containers to access)
# :Z applies a unique context (only this container can access)
Conclusion
Podman on RHEL 9 provides a daemon-less, rootless container runtime that is the preferred choice for security-conscious RHEL deployments. Running containers rootlessly means a container breakout vulnerability cannot escalate to host root access — the attacker would be constrained to the user’s UID and permissions. The SELinux volume labels (:z and :Z) are the most commonly missed configuration when migrating from Docker to Podman on RHEL, and omitting them results in “Permission denied” errors when containers try to access volume-mounted files.
Next steps: How to Configure Podman Compose on RHEL 9, How to Install Docker Engine on RHEL 9, and How to Install Kubernetes on RHEL 9.