How to Install and Use Podman with systemd Socket Activation on RHEL 7
Podman is a daemonless container engine developed by Red Hat that provides a Docker-compatible CLI while operating without a central privileged daemon. On RHEL 7, Podman integrates deeply with systemd, enabling containers to be managed as first-class system services, started on-demand via socket activation, and run by non-root users with full persistence across reboots. This tutorial covers installing Podman, enabling the REST API via socket activation, generating systemd unit files from running containers, enabling user-level service persistence with loginctl enable-linger, managing containers as systemd user services, and comparing Podman’s architecture with Docker’s always-on daemon model.
Prerequisites
- RHEL 7 with a valid subscription and access to the
extrasorrhel-7-server-extras-rpmsrepository - sudo or root access for system-level operations
- A non-root user account for running rootless containers
- Basic familiarity with systemd and Linux containers
Step 1: Install Podman on RHEL 7
Podman is available in the RHEL 7 Extras repository. Ensure this repository is enabled before installation.
# Enable the RHEL 7 Extras repository
sudo subscription-manager repos --enable=rhel-7-server-extras-rpms
# Install Podman and supporting tools
sudo yum install -y podman podman-docker
# Verify the installation
podman --version
podman info
# Check the storage configuration
podman info | grep -A5 store
The podman-docker package installs a wrapper script that aliases docker to podman, making most Docker-based scripts and documentation directly compatible without modification. Podman stores images and container data in /var/lib/containers for root and ~/.local/share/containers for non-root users.
Step 2: Run Your First Container
Verify Podman is working correctly by running a simple container. Unlike Docker, this requires no background daemon to be running.
# Pull and run a container (no daemon needed)
podman run --rm docker.io/library/hello-world
# Run an interactive RHEL UBI container
podman run -it --rm registry.access.redhat.com/ubi7/ubi:latest bash
# Inside the container, verify the environment
cat /etc/redhat-release
exit
# Run a web server in detached mode
podman run -d --name mynginx -p 8080:80 docker.io/library/nginx:alpine
# Verify it is running
podman ps
curl -I http://localhost:8080
# Stop and remove the container
podman stop mynginx
podman rm mynginx
Step 3: Enable the Podman REST API with systemd Socket Activation
Podman provides a REST API that is compatible with the Docker API, enabling tooling like Portainer, docker-compose, and custom CI scripts to communicate with it. On RHEL 7, this is exposed through a systemd socket-activated service — meaning the REST API process only starts when a client connects to the socket, rather than running continuously as a daemon.
System-Level (Root) Socket
# Enable and start the Podman system socket
sudo systemctl enable podman.socket
sudo systemctl start podman.socket
# Verify the socket is active
sudo systemctl status podman.socket
ls -lh /run/podman/podman.sock
# Test the REST API
sudo curl --unix-socket /run/podman/podman.sock http://d/v4.0.0/info | python -m json.tool
# List containers via the REST API
sudo curl --unix-socket /run/podman/podman.sock http://d/v4.0.0/containers/json
User-Level (Rootless) Socket
# Enable the user-level Podman socket (run as non-root user)
systemctl --user enable podman.socket
systemctl --user start podman.socket
# Check socket location
systemctl --user status podman.socket
ls -lh $XDG_RUNTIME_DIR/podman/podman.sock
# Test
curl --unix-socket $XDG_RUNTIME_DIR/podman/podman.sock
http://d/v4.0.0/info | python -m json.tool
Step 4: Generate systemd Unit Files with podman generate systemd
Podman includes a built-in command to generate production-ready systemd unit files from a running container. The --new flag instructs systemd to pull and create a fresh container on each start, rather than relying on a specific container ID that may no longer exist after a reboot.
# First, run a container that you want to manage with systemd
podman run -d
--name myredis
-p 6379:6379
-v /opt/redis-data:/data:z
docker.io/library/redis:7-alpine
redis-server --appendonly yes
# Generate a systemd unit file using --new (recommended for persistence)
podman generate systemd --new --name myredis --files --container-prefix pod
# List the generated files
ls -lh *.service
cat container-myredis.service
The generated unit file includes the full podman run command so the container can be re-created from scratch by systemd. This is more resilient than referencing a specific container ID, which would break after podman rm.
Step 5: Configure User Systemd Services (~/.config/systemd/user/)
Copy the generated unit file to the correct location for user-level systemd services. User services run in the user’s own systemd instance and do not require root privileges.
# Create the user systemd directory
mkdir -p ~/.config/systemd/user/
# Copy the generated service file
cp container-myredis.service ~/.config/systemd/user/
# Reload the user systemd daemon to discover the new unit
systemctl --user daemon-reload
# Enable the service to start automatically
systemctl --user enable container-myredis.service
# Start the service
systemctl --user start container-myredis.service
# Check status
systemctl --user status container-myredis.service
# View logs
journalctl --user -u container-myredis.service -f
Step 6: Enable Linger for Non-Root User Persistence
By default, systemd user services only run while the user is logged in. When the user logs out, their entire user session — including all running containers — is terminated. The loginctl enable-linger command configures the system to maintain the user’s systemd session even when no login session is active, enabling containers to persist across reboots without requiring root.
# Enable linger for the current user
sudo loginctl enable-linger $(whoami)
# Verify linger is enabled
loginctl show-user $(whoami) | grep Linger
# Also verify using the file that linger creates
ls -lh /var/lib/systemd/linger/$(whoami)
# After enabling linger, user services start at boot automatically
# Test by rebooting and checking container status
# sudo systemctl reboot
# (After reboot)
# podman ps
# systemctl --user status container-myredis.service
With linger enabled, the user’s systemd manager starts at boot (before login) and all enabled user units — including containerized services — start automatically. This is the Podman equivalent of Docker’s daemon auto-starting containers with --restart always.
Step 7: Understanding Socket Activation
Socket activation is a systemd feature where the kernel holds open a socket and activates the corresponding service only when an incoming connection arrives. This reduces resource usage when the service is idle and eliminates race conditions where dependent services start before the socket is ready.
Podman’s socket unit file works as follows:
# View the socket unit definition
cat /usr/lib/systemd/system/podman.socket
A typical Podman socket unit looks like this:
[Unit]
Description=Podman API Socket
Documentation=man:podman-system-service(1)
[Socket]
ListenStream=%t/podman/podman.sock
SocketMode=0660
[Install]
WantedBy=sockets.target
And the corresponding service unit:
[Unit]
Description=Podman API Service
Requires=podman.socket
After=podman.socket
Documentation=man:podman-system-service(1)
StartLimitIntervalSec=0
[Service]
Type=exec
KillMode=process
Environment=LOGGING="--log-level=info"
ExecStart=/usr/bin/podman $LOGGING system service
[Install]
WantedBy=multi-user.target
When a client connects to podman.sock, systemd activates the podman.service to handle the request. After a configurable idle timeout, the service process exits and waits for the next connection. This is fundamentally different from Docker, which runs dockerd as a permanent root daemon regardless of whether any containers are running.
Step 8: Comparing Podman and Docker Architecture
Understanding the architectural differences between Podman and Docker helps you make better operational decisions on RHEL 7.
- Docker requires a root-privileged daemon (
dockerd) running at all times. All container operations pass through this single daemon process. Ifdockerdcrashes, management of all running containers is disrupted. - Podman has no persistent daemon. Each
podmancommand is a self-contained process that directly uses the Linux kernel’scgroups,namespaces, andseccompinterfaces. Container processes are direct children of thepodmancommand or ofconmon(container monitor), not of a daemon. - Security: Podman can run containers as a fully unprivileged user with no elevated processes in the chain. Docker rootless mode exists but requires additional configuration and is less mature on RHEL 7.
- systemd integration: Podman containers managed as systemd services participate in the full systemd lifecycle —
journaldlogging, dependency ordering, resource limits via cgroups v1 on RHEL 7, and restart policies.
# Show that podman has no daemon
ps aux | grep -E "dockerd|containerd" | grep -v grep
ps aux | grep -E "podman" | grep -v grep
# Each podman run spawns a conmon monitor process per container
podman run -d --name testbox docker.io/library/alpine sleep 3600
ps aux | grep conmon
# Clean up
podman stop testbox
podman rm testbox
Conclusion
You have installed Podman on RHEL 7, enabled its REST API socket using systemd socket activation, and generated production-ready systemd unit files from live containers using podman generate systemd --new. You placed user-level service units in ~/.config/systemd/user/, managed them with systemctl --user, and used loginctl enable-linger to ensure containers survive user logout and start automatically at boot. You also explored the socket activation mechanism that allows the Podman REST API to respond on-demand without a permanently running daemon, and examined how this compares to Docker’s always-on daemon architecture. Podman’s deep systemd integration makes it a natural fit for RHEL 7 environments where container workloads should behave like any other managed system service.