Daemonless architecture and real rootless security in production
Podman promises a compatible replacement for Docker while deliberately dropping the root-owned background daemon and enabling containers that run entirely without root privileges. For hosting environments serving multiple customers on one server, that is not a cosmetic detail but a fundamentally different security model that directly shapes attack surface and blast radius.
Table of Contents
- 1. Why Podman needs no daemon at all
- 2. How rootless mode actually works
- 3. Concrete security benefits over root containers
- 4. Compatibility with the Docker CLI and Docker images
- 5. systemd integration with podman generate systemd
- 6. Quadlet: describing containers declaratively as systemd units
- 7. Practical example: running Magento containers rootless
- 8. Pods as bundles of several containers
- 9. Limits of rootless mode and when root containers still make sense
- 10. Summary
- 11. FAQ
1. Why Podman needs no daemon at all
The Docker daemon dockerd runs permanently as a root process and manages every container centrally through a Unix socket. Anyone who can reach that socket effectively gets root privileges on the host, because the daemon itself executes requested actions with full privileges. This architecture grew historically and is convenient, but on shared hosts or build servers it is a substantial risk, since a compromised container process reaching the socket can potentially take over the entire host.
Podman skips this central daemon entirely. Every podman run invocation starts an independent process that creates containers directly through kernel interfaces, typically with conmon as a lightweight monitor process per container and runc or crun as the OCI compliant runtime underneath. If a container process goes away, only that one container is affected, there is no central single point of failure whose crash drags down every running container at once.
# Podman process tree per container instead of one central daemon
ps -ef | grep -E "conmon|crun"
# No socket, no central authority: every call stands on its own
podman run -d --name shop-cache redis:7-alpine
podman ps
2. How rootless mode actually works
In rootless mode, the entire container process tree runs under the UID of a regular, unprivileged user. This is made possible by user namespaces: inside the container, the process appears as root with UID 0, while on the host that same UID is mapped to an unprivileged range assigned via /etc/subuid and /etc/subgid. Root inside the container is therefore a purely logical construct with no real host privileges attached.
Networking, storage, and cgroup management in rootless mode rely on userspace tools instead of kernel privileges: slirp4netns or the more performant pasta handle networking without root rights, and the fuse-overlayfs storage driver replaces the classic overlay driver that would otherwise require root. The cost is a certain performance overhead compared to real kernel mounts, though for most web workloads that overhead barely registers.
# Check the subuid and subgid range assigned to the current user
grep "$USER" /etc/subuid /etc/subgid
# Run a container as an unprivileged user, root inside the container
# stays a process with a mapped, unprivileged UID on the outside
podman run --rm -it alpine id
3. Concrete security benefits over root containers
The most important effect of rootless mode shows up during a container escape: if an attacker manages to break out of the container, they land on the host not as root, but as the unprivileged user Podman was running under. Even a successful escape does not grant host root, only the restricted rights of a regular account, which drastically limits the blast radius.
On multi tenant hosts, as commonly found in Magento hosting with several customers sharing one machine, this model can be used directly for isolation between customers: each customer gets a dedicated Linux user and runs their containers exclusively under that UID. A compromised container belonging to one customer then cannot, by design, read another customer's files or interfere with their containers, because the operating system's own user isolation kicks in long before any container specific mechanism even comes into play.
4. Compatibility with the Docker CLI and Docker images
Podman deliberately implements the same command line syntax as Docker: podman run, podman build, podman ps, and most flags behave identically, so existing scripts often run unmodified. Anyone who wants an especially frictionless switch can simply set alias docker=podman, and many distributions even ship a dedicated podman-docker package that redirects the docker command system wide to Podman.
Images cause no friction either: Podman pulls standard Docker images from the Docker registry or from private registries without any conversion, since both rely on the shared OCI image format. A Dockerfile builds unchanged with podman build, and the resulting image can afterward be pushed to a registry and reused with Docker just the same. One difference remains around Docker Compose: Podman ships its own implementation via podman-compose or native podman compose support, which is not a hundred percent identical to the original in every detail.
# Build an existing Dockerfile unchanged with Podman
podman build -t shop-app:latest .
# Run a Docker Compose file with Podman
podman compose -f docker-compose.yml up -d
5. systemd integration with podman generate systemd
Unlike Docker, which keeps containers alive permanently through its own daemon, Podman deliberately leaves lifecycle management to systemd, the init system already running on most Linux distributions anyway. The podman generate systemd command turns a running container into a matching systemd unit file complete with start, stop, and restart logic, so containers start automatically at boot and get restarted by systemd itself after a crash, with no extra wrapper service involved.
These generated units can be registered both as system wide root services and, which matters especially for rootless mode, as user units under systemctl --user. That means the entire container lifecycle runs inside the session of an unprivileged user, including logging via journalctl and resource limits managed through the cgroups the user manager owns.
# Turn a running container into a systemd unit file
podman generate systemd --new --files --name shop-cache
# Register and activate the unit file for the current user
mkdir -p ~/.config/systemd/user
mv container-shop-cache.service ~/.config/systemd/user/
systemctl --user daemon-reload
systemctl --user enable --now container-shop-cache.service
6. Quadlet: describing containers declaratively as systemd units
Since Podman 4.4, Quadlet has increasingly replaced generated units: instead of manually starting a container and generating a unit from it afterward, a .container file describes the desired state declaratively, similar to a Kubernetes manifest, and systemd itself generates the matching service unit at runtime. Configuration changes now happen directly in a versionable text file rather than through an imperative generate step after every restart.
Quadlet files live under ~/.config/containers/systemd/ for rootless setups or /etc/containers/systemd/ for root operation, and get translated into regular units automatically by podman-system-generator at systemd startup. For production setups this is the recommended path, since the entire configuration can be versioned in Git and rolled out through configuration management, instead of relying on manually generated unit files that go stale.
# ~/.config/containers/systemd/shop-cache.container
[Unit]
Description=Redis cache for the Magento shop
After=network-online.target
[Container]
Image=docker.io/library/redis:7-alpine
PublishPort=127.0.0.1:6379:6379
Volume=shop-cache-data.volume:/data
[Service]
Restart=always
[Install]
WantedBy=default.target
7. Practical example: running Magento containers rootless
A realistic setup splits a Magento stack across several rootless Podman containers under one dedicated system user UID: PHP FPM, Nginx as a reverse proxy, and Redis for session and cache. Because ports below 1024 cannot be bound by default in rootless mode, Nginx listens internally on a high port, while a root owned, system wide reverse proxy such as another Nginx instance or Traefik terminates the actual port 443 externally and forwards traffic internally to the unprivileged container.
File access between host and container hinges on the UID mapping: since root inside the container maps to an unprivileged host UID, volume mounts need podman unshare chown to bring ownership onto the correctly mapped UID, so that PHP FPM inside the container actually has write access to var and pub/media, without the host user outside the user namespace needing root rights at all.
# Prepare the Magento directory for the rootless container namespace
podman unshare chown -R 82:82 var pub/media
# Start the PHP FPM container rootless with mounted Magento files
podman run -d --name shop-php \
--userns=keep-id \
-v "$(pwd):/var/www/html:Z" \
--network shop-net \
magento-php-fpm:8.4
8. Pods as bundles of several containers
Beyond the single container, Podman also implements the pod concept, borrowed directly from the Kubernetes unit of the same name: multiple containers inside a pod share one network namespace and therefore localhost, so PHP FPM and Nginx inside the same pod can talk to each other over 127.0.0.1 without needing a separate container network with DNS resolution. Only the pod itself exposes ports externally, individual containers inside it stay invisible from outside.
This model makes a later migration to Kubernetes considerably easier, because a Podman pod structurally matches a Kubernetes pod and can even be exported directly into a Kubernetes manifest with podman generate kube. For smaller hosting setups without full orchestration, a single rootless pod per customer or project remains a pragmatic, well isolated solution regardless.
# Create a pod with a shared network for the Magento stack
podman pod create --name shop-pod -p 127.0.0.1:8080:8080
podman run -d --pod shop-pod --name shop-php magento-php-fpm:8.4
podman run -d --pod shop-pod --name shop-nginx nginx:1.27-alpine
9. Limits of rootless mode and when root containers still make sense
Rootless mode has real limits too: some network features, such as binding low ports directly inside the container, certain VLAN configurations, or macvlan networks with a dedicated MAC address, require genuine kernel privileges and either fail entirely in rootless mode or only work through workarounds. The performance overhead of fuse-overlayfs compared to native kernel mounts also becomes measurable on very IO heavy workloads, for example database containers with high write throughput.
For such cases, running Podman as root remains a valid option that is still noticeably safer than Docker, since even root mode has no permanent, privileged daemon, and each container process tree is managed independently. The pragmatic recommendation for hosting environments is to establish rootless containers as the default and reserve root operation for cases where concrete technical requirements demand it, rather than running everything privileged out of pure habit.
| Criterion | Docker | Podman Rootless | Podman Root |
|---|---|---|---|
| Daemon | dockerd, permanently as root | no daemon, one process tree per container | no daemon, one process tree per container |
| Root rights to start a container | required via socket access | not required | required |
| Risk on container escape | effectively host root possible | only rights of the unprivileged user | host root possible |
| Storage driver | overlay2, kernel based | fuse-overlayfs, userspace | overlay2, kernel based |
| systemd integration | via external wrapper tools | native via generate systemd or Quadlet | native via generate systemd or Quadlet |
Mironsoft
Server administration, Docker hosts, and performance tuning
Linux servers nobody on the team really understands anymore?
We handle setup, hardening, and performance tuning of Linux servers and Docker hosts for Magento deployments, documented and traceable instead of grown and unclear.
Server Audit
Review the existing server configuration for security gaps and performance bottlenecks.
Docker Host Setup
Set up and secure production-ready Docker environments for Magento cleanly.
Monitoring & Tuning
Measure resource usage and tune systemd, kernel, and services with purpose.
10. Summary
Podman Rootless
Architecture
No central daemon, one process tree per container
Security gain
A container escape lands as an unprivileged user, not as root
Compatibility
Docker CLI, Dockerfile, and OCI images work unchanged
Operations
podman generate systemd or Quadlet for autostart and restart