- Published on
Docker vs Podman: Which One for Your Homelab?


- Name
- Chad Wilson
- @NetPenguins
Series
Full Stack Todo App
- 01Todo API Creation with FastAPI
- 02Building a User Interface for Your To-Do Application
- 03Securing FastAPI with OAuth2 and JWT
- 04Build and Deploy the Todo App with Docker Compose
- 05Docker vs Podman: Which One for Your Homelab?
- 06Keycloak SSO with FastAPI
- 07Authentik SSO with FastAPI
Welcome back! In the previous post we containerized the todo app with Docker and Docker Compose. If you are running this on a personal server or homelab, you may have come across Podman as an alternative and wondered what the actual difference is. This post breaks it down.
What They Have in Common
Both Docker and Podman are container runtimes that implement the OCI (Open Container Initiative) specification. That means:
- Images built with Docker run on Podman and vice versa
- Dockerfiles work with both (
podman buildunderstands the same syntax) - Docker Hub images pull and run identically on both
- Docker Compose files are compatible with Podman Compose
For the todo app we built, switching from Docker to Podman requires almost no changes.
The Core Difference: The Daemon
Docker uses a persistent background daemon (dockerd) that runs as root. Every docker command you run communicates with that daemon over a Unix socket. The daemon owns all the containers and images on the system.
Podman is daemonless. There is no background process. When you run podman run, it forks a child process directly and that process becomes the container. When the container stops, nothing lingers.
Rootless Containers
Because Docker's daemon runs as root, any user with access to the Docker socket effectively has root on the host. This is a known attack surface. If an attacker can write to the Docker socket, they can mount the host filesystem into a container and escape.
Podman supports rootless containers: containers that run entirely as your regular user, with no root involvement. The container process runs under your UID, and user namespaces handle the mapping between container root and your unprivileged user.
For a homelab where you do not want a compromised container to be able to touch the rest of your system, rootless Podman is a real security improvement.
Docker has experimental rootless mode, but it requires additional setup and is not the default. With Podman, rootless is the default.
Systemd Integration
In a homelab you probably want containers to start on boot, restart on failure, and behave like normal services. With Docker you typically rely on restart: always in Compose or write a separate systemd unit to manage it.
Podman has first-class systemd integration. You can generate a systemd unit file directly from a running container:
podman generate systemd --new --name todo-api > ~/.config/systemd/user/todo-api.service
systemctl --user enable --now todo-api
This creates a proper systemd service that starts the container on login, restarts on failure, and respects systemctl stop. The --user flag means it runs under your user session with no root required.
For server deployments managed by systemd (which is most modern Linux distros), this is cleaner than Docker's approach.
Pods
Podman introduced the concept of a pod borrowed from Kubernetes. A pod is a group of containers that share a network namespace, meaning they can communicate over localhost without any special networking configuration.
Our todo app is a natural fit for a pod. The API and UI share a pod, communicate internally, and only the UI port needs to be exposed externally.
podman pod create --name todo-app -p 3000:80 -p 8000:8000
podman run -d --pod todo-app --name todo-api todo-api:latest
podman run -d --pod todo-app --name todo-ui todo-ui:latest
This mirrors how Kubernetes works. If you ever move from a homelab to a Kubernetes cluster, your mental model transfers directly.
Docker Compose vs Podman Compose
If you want to keep using the docker-compose.yml format we set up in the previous post, Podman Compose is a community project that interprets Compose files using Podman under the hood.
pip install podman-compose
podman-compose up --build
Most Compose syntax is supported. The gaps are mostly around advanced networking and Docker-specific extensions.
Red Hat also maintains Quadlet, a newer way to define containers as systemd unit files with a declarative syntax. Worth looking at if you are running Fedora, RHEL, or any systemd-first distro.
Installing Podman
On most Linux distros:
# Fedora / RHEL / CentOS
sudo dnf install podman
# Ubuntu / Debian
sudo apt install podman
# Arch
sudo pacman -S podman
On macOS, Podman runs a lightweight Linux VM under the hood:
brew install podman
podman machine init
podman machine start
Migrating the Todo App to Podman
Because we used standard OCI images and a Compose file, the migration is minimal. From the repo root:
# Build the images
podman build -f todo-api/Dockerfile -t todo-api:latest .
podman build -f todo-ui/Dockerfile --build-arg VITE_API_URL=http://localhost:8000 -t todo-ui:latest .
# Run with Podman Compose
podman-compose up -d
Or if you want the systemd approach for a server:
# Create a pod
podman pod create --name todo-app -p 8000:8000 -p 3000:80
# Start containers in the pod
podman run -d --pod todo-app \
--env-file .env \
-v todo_data:/app/data \
--name todo-api todo-api:latest
podman run -d --pod todo-app \
--name todo-ui todo-ui:latest
# Generate systemd units
mkdir -p ~/.config/systemd/user
podman generate systemd --new --files --name todo-api
podman generate systemd --new --files --name todo-ui
mv container-todo-api.service container-todo-ui.service ~/.config/systemd/user/
systemctl --user daemon-reload
systemctl --user enable --now container-todo-api container-todo-ui
Both containers now start on login, restart on failure, and are managed by systemd like any other service on the box.
When to Stick With Docker
Podman is not universally better. There are real reasons to stay on Docker.
Ecosystem tooling. Docker has been around longer. Tools like Portainer, Watchtower, and many CI platforms have deeper Docker integration. Podman support is improving but not always at parity.
Docker Desktop. On macOS or Windows with a need for a graphical interface, Docker Desktop is more polished than the Podman equivalent. For local dev on a laptop the convenience is real.
Team familiarity. If everyone knows Docker and your CI already uses it, introducing Podman adds overhead with uncertain benefit. The security win from rootless mode matters more on a server than on a developer laptop.
docker compose v2. Docker Compose v2 is now baked into the Docker CLI as docker compose (no hyphen). It is faster and better maintained than the old docker-compose v1, and Podman Compose has not fully caught up on all features.
The Summary
| Docker | Podman | |
|---|---|---|
| Architecture | Daemon-based | Daemonless |
| Default permissions | Root daemon | Rootless |
| Systemd integration | Manual | Native |
| Kubernetes alignment | Limited | Pod model matches K8s |
| Ecosystem / tooling | Larger | Growing |
| Compose support | Native (v2) | podman-compose (community) |
| macOS/Windows GUI | Docker Desktop (polished) | Podman Desktop (improving) |
For a homelab server running Linux with systemd, Podman wins on security and integration. For local development or team environments where the Docker ecosystem matters, Docker is the easier choice. Both are legitimate tools.
Up Next
The next posts move from rolling our own auth to using a dedicated identity provider. We will look at Keycloak, the heavyweight option with enterprise features, and Authentik, the self-hosted alternative that is easier to stand up in a homelab.