
If you run containers on a Linux server, you already know that Docker’s default setup requires a root-level daemon sitting between you and every container you run. That daemon is a single point of failure, a security risk, and an unnecessary layer of complexity on modern systems. Podman solves all three problems at once by removing the daemon entirely.
This guide walks you through exactly how to install Podman on Ubuntu 26.04 LTS, configure rootless containers, set up systemd integration using Quadlets, run multi-container applications with Podman Compose, and build your own custom container images. Every command in this article was tested on Ubuntu 26.04 LTS (Resolute Raccoon) running kernel 7.0.0-10-generic with Podman 5.7.0 from Ubuntu’s default repositories.
By the end, you will have a fully working Podman setup capable of handling real production workloads, with zero dependency on a root daemon and full systemd integration baked in from the start.
Here is what this guide covers:
- Installing Podman 5.7.0 from Ubuntu 26.04’s native APT repositories
- Enabling and managing the Podman API socket
- Pulling images, running containers, and reading logs
- Configuring rootless containers under a non-root user
- Creating Kubernetes-style pods
- Managing containers as systemd services with Quadlets
- Building custom container images with a Containerfile
- Running multi-service apps with Podman Compose
- Enabling Docker CLI compatibility
What Is Podman and Why Should You Use It?
Podman (short for Pod Manager) is an open-source, daemonless container engine that builds, runs, and manages OCI-compatible (Open Container Initiative) containers. Unlike Docker, Podman does not rely on a background process running as root. Each container is a direct child process of the user who starts it, which completely changes the security model.
Here is why that matters on a production Ubuntu server:
- No daemon means no single point of failure. With Docker, if
dockerdcrashes, every running container stops with it. With Podman, containers are independent processes. A crashed container affects nothing else. - Rootless by default. Podman runs containers under your own UID without requiring you to join any special group or configure extra permissions. A container breakout lands in an unprivileged user account, not root.
- Native systemd integration. Podman 5.7.0 supports Quadlets, which let you declare containers as simple INI-style files that systemd manages natively.
- No external repo needed on Ubuntu 26.04. Podman 5.7.0 ships in Ubuntu’s default APT repositories, which means no third-party PPAs, no signing key juggling, and no version drift.
Podman vs Docker: Architecture Comparison
Both tools run OCI containers and accept nearly identical CLI commands. The differences are architectural.
| Feature | Podman | Docker |
|---|---|---|
| Architecture | Daemonless, each container is a child process | Requires persistent dockerd daemon |
| Root requirement | Rootless by default | Requires root or docker group membership |
| Pod support | Native Kubernetes-style pods | No native pod concept |
| Systemd integration | Quadlets (first-class support) | Requires custom unit files |
| API socket | Optional, on-demand | /var/run/docker.sock always active |
| Compose support | podman-compose from Ubuntu repos |
docker compose plugin |
| Container runtime | crun with cgroups v2 |
runc (default) |
| Resource overhead | Lower (no daemon) | Higher (dockerd + containerd) |
For most servers where security posture and tight systemd integration matter, Podman is the better choice. Docker remains relevant for teams using Docker Swarm or CI toolchains with hard Docker dependencies.
Prerequisites
Before you start, make sure your environment meets these requirements:
- Operating system: Ubuntu 26.04 LTS (Resolute Raccoon), kernel 7.0 or later
- User access: A non-root user account with
sudoprivileges - Hardware minimums: 2 GB RAM, 20 GB available disk space
- Network: Active internet connection for pulling container images
- Conflicting software: Remove Docker CE, LXD, or any existing container runtimes first to avoid storage driver and cgroup v2 conflicts
Verify your Ubuntu version before continuing:
lsb_release -a
Expected output:
No LSB modules are available.
Distributor ID: Ubuntu
Description: Ubuntu 26.04 LTS
Release: 26.04
Codename: resolute
If your system shows an older Ubuntu release, this guide does not apply. Podman 5.7.0 is specific to Ubuntu 26.04’s package versions.
Step 1: Update Your System Package Index
Start by refreshing your APT cache:
sudo apt update
Why this step matters: APT stores package metadata locally in a cache. Without updating, your system may resolve podman to an older cached version instead of the current 5.7.0 release in Ubuntu 26.04’s repositories. This single step is the most common reason users end up with version mismatches.
Expected output (partial):
Hit:1 http://archive.ubuntu.com/ubuntu resolute InRelease
Hit:2 http://archive.ubuntu.com/ubuntu resolute-updates InRelease
Reading package lists... Done
Building dependency tree... Done
Step 2: Install Podman on Ubuntu 26.04 LTS
With the package index updated, install Podman directly from Ubuntu’s default repositories:
sudo apt install -y podman
Why no external PPA is needed: Ubuntu 26.04 includes Podman 5.7.0 in its main repository. This is a significant improvement over earlier Ubuntu releases, which required adding the Kubic project PPA. Fewer external sources mean fewer security risks and simpler long-term maintenance.
The installer pulls in crun, conmon, netavark, aardvark-dns, and buildah as dependencies. These are the components that make up Podman’s full runtime stack on Ubuntu 26.04.
Step 2.1: Verify the Installed Version
Confirm Podman installed correctly:
podman --version
Expected output:
podman version 5.7.0
Step 2.2: Inspect the Full Runtime Environment
Run podman info to see the complete runtime configuration:
podman info
Key fields to review in the output:
host:
cgroupManager: systemd
cgroupVersion: v2
kernel: 7.0.0-10-generic
os: linux
store:
graphDriverName: overlay
graphRoot: /var/lib/containers/storage
version:
Version: 5.7.0
GoVersion: go1.25.0
Why check this output: podman info confirms three critical settings. First, cgroupVersion: v2 means Podman uses the modern cgroup hierarchy, which is required for full rootless container support. Second, graphDriverName: overlay is the recommended storage driver for performance. Third, cgroupManager: systemd ensures containers integrate cleanly with systemd for resource management and Quadlet support.
Step 3: Enable the Podman API Socket
Podman provides two components for managing containers: the podman CLI for direct use, and podman.socket for API-based remote access.
Enable the socket to start at boot:
sudo systemctl enable podman.socket
Start the socket now without rebooting:
sudo systemctl start podman.socket
Confirm the socket is active and listening:
sudo systemctl status podman.socket
Expected status line:
Active: active (listening) since Wed 2026-05-06 05:30:00 UTC; 3s ago
Why “listening” matters: A socket unit can report active while still in a failed sub-state. The word listening specifically confirms that the socket file exists at /run/podman/podman.sock and is accepting connections. Tools like Podman Desktop, CI/CD pipelines, and container management UIs connect through this socket. Without it, those tools cannot communicate with Podman.
Step 4: Pull Images and Run Your First Container
Step 4.1: Pull an Image
Pull the official Nginx image from Docker Hub:
podman pull docker.io/library/nginx:latest
Why use the fully qualified image name: Unlike Docker, Podman does not default to Docker Hub automatically. It checks multiple registries defined in /etc/containers/registries.conf. Specifying docker.io/library/ explicitly removes any ambiguity and prevents silent failures on servers with custom registry configurations.
Step 4.2: Run the Container
Launch Nginx in detached mode on port 8080:
podman run -d --name web-server -p 8080:80 docker.io/library/nginx:latest
What these flags do:
-druns the container in the background and returns your terminal immediately--name web-servergives the container a human-readable name instead of a random ID-p 8080:80maps port 8080 on your host to port 80 inside the container
Step 4.3: Verify the Container Is Running
podman ps
Expected output:
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
094e545dffd6 docker.io/library/nginx:latest nginx -g daemon o... 2 seconds ago Up 2 seconds 0.0.0.0:8080->80/tcp web-server
Step 4.4: Test and Check Logs
Test the container responds to HTTP requests:
curl -s http://localhost:8080 | head -5
Check the startup logs:
podman logs web-server
Why check logs immediately after launch: Container logs reveal whether the application inside started cleanly or silently failed after the container reached Up status. A container can show as running while its main process is stuck in a crash loop. Checking logs right away is a habit that prevents wasted troubleshooting time later.
Step 5: Configure Rootless Containers
Rootless containers are Podman’s biggest practical security advantage. They run entirely under a non-root user account with no special group membership, no sudo, and no persistent root socket.
Step 5.1: Create a Dedicated User
sudo useradd -m -s /bin/bash devuser
Why a dedicated user: Isolating containers under a dedicated account limits the impact of any container incident. It also enables per-user resource limits via cgroups v2, and keeps container storage separate from other users’ home directories.
Step 5.2: Enable Systemd Lingering
sudo loginctl enable-linger devuser
Why lingering is non-negotiable for server use: Without it, devuser‘s entire systemd session, and every container running inside it, terminates the moment they log out. Enabling lingering keeps the user’s process tree alive across sessions, so containers keep running uninterrupted.
Step 5.3: Run a Container as the Non-Root User
su - devuser
podman pull docker.io/library/nginx:latest
podman run -d --name my-nginx -p 9090:80 docker.io/library/nginx:latest
Step 5.4: Confirm Rootless Mode
podman info --format "{{.Host.Security.Rootless}}"
Expected output:
true
Exit back to your admin account when done:
exit
Step 6: Create Kubernetes-Style Pods
A pod in Podman is a group of containers that share the same network namespace. Inside a pod, containers communicate over localhost without any exposed ports between them.
Create a pod with ports defined for both Nginx and Redis:
podman pod create --name webapp -p 8090:80 -p 6380:6379
Why ports are defined at the pod level: All containers in a pod share the network namespace of the pod’s infra (pause) container. Ports must be declared when creating the pod, not when adding individual containers.
Add containers to the pod:
podman run -d --pod webapp --name webapp-nginx docker.io/library/nginx:latest
podman run -d --pod webapp --name webapp-redis docker.io/library/redis:latest
Verify the pod and its containers:
podman pod ps
podman ps --pod
Nginx and Redis can now reach each other over localhost inside the pod. This mirrors how Kubernetes pods work, which makes your local development environment structurally identical to production when you later deploy on a Kubernetes cluster.
Step 7: Manage Containers with systemd Quadlets
Quadlets are the modern way to run Podman containers as systemd services. You write a simple .container file, and systemd’s generator converts it into a proper unit file at boot. This replaces the older podman generate systemd approach, which produced fragile unit files that broke whenever the container configuration changed.
Create the Quadlet file:
sudo vi /etc/containers/systemd/nginx.container
Add this configuration:
[Container]
Image=docker.io/library/nginx:latest
ContainerName=nginx-quadlet
PublishPort=8085:80
[Service]
Restart=always
[Install]
WantedBy=multi-user.target
Why Restart=always: Without this directive, a crashed container stays down until someone manually restarts it. On a production server, you want systemd to handle restarts automatically.
Reload systemd and start the service:
sudo systemctl daemon-reload
sudo systemctl start nginx.service
Why daemon-reload is mandatory: Quadlet files only become active unit files when systemd re-scans its generator directories. Skipping this step causes systemd to fail with a “unit not found” error because the generated unit does not exist yet.
Enable autostart and verify:
sudo systemctl enable nginx.service
systemctl status nginx.service
Expected status:
Active: active (running) since Wed 2026-05-06 08:46:10 UTC; 2s ago
Step 8: Build a Custom Container Image
Podman uses Buildah under the hood to build images. Buildah performs fully rootless, daemonless builds, meaning no root process is involved at any stage. You can use either a Dockerfile or a Containerfile (Podman’s preferred name) as the build definition.
Create a project directory:
mkdir -p /opt/myapp && cd /opt/myapp
Create the application file:
nano /opt/myapp/app.py
Add a minimal Flask application:
from flask import Flask
app = Flask(__name__)
@app.route('/')
def hello():
return 'Hello from Podman on Ubuntu 26.04!'
if __name__ == '__main__':
app.run(host='0.0.0.0', port=5000)
Create the Containerfile:
vi /opt/myapp/Containerfile
FROM docker.io/library/python:3-slim
WORKDIR /app
RUN pip install flask
COPY app.py .
EXPOSE 5000
CMD ["python", "app.py"]
Build the image:
podman build -t myflask:latest -f Containerfile .
Why tag explicitly with -t: Unnamed images get stored as <none>:<none>, making them impossible to reference by name later. Always tag during build.
Run and test the custom image:
podman run -d --name flask-app -p 5000:5000 localhost/myflask:latest
curl http://localhost:5000
Expected output:
Hello from Podman on Ubuntu 26.04!
Step 9: Run Multi-Service Apps with Podman Compose
podman-compose translates docker-compose.yml files into native Podman commands. It requires no Docker daemon or socket, which makes it the cleanest migration path for existing Compose-based projects.
Install it from Ubuntu’s repositories:
sudo apt install -y podman-compose
podman-compose --version
Expected output:
podman-compose version 1.5.0
Create a sample project:
mkdir -p /opt/compose-demo && cd /opt/compose-demo
Create the compose file:
vi docker-compose.yml
services:
web:
image: docker.io/library/nginx:latest
ports:
- "8095:80"
cache:
image: docker.io/library/redis:latest
Start all services in the background:
podman-compose up -d
Check running services scoped to this project:
podman-compose ps
Why use podman-compose ps instead of podman ps: podman-compose ps scopes its output to the current project’s containers. On a busy server with dozens of containers running, plain podman ps lists everything at once and makes it harder to spot project-specific issues.
Stop and clean up when done:
podman-compose down
Step 10: Enable Docker CLI Compatibility
If your CI/CD pipelines or automation scripts use hardcoded docker commands, install the podman-docker compatibility package:
sudo apt install -y podman-docker
This creates a docker alias pointing to Podman. Commands like docker build, docker ps, and docker push now route through Podman transparently, requiring zero changes to your existing scripts.
Suppress the emulation notice for cleaner script output:
sudo touch /etc/containers/nodocker
Troubleshooting Common Podman Issues on Ubuntu 26.04
Error: “cgroup v1 is not supported”
Cause: Your VM or server is booting with the legacy cgroup v1 hierarchy instead of v2, which Podman 5.7.0 requires.
Fix: Verify your cgroup version with:
cat /sys/fs/cgroup/cgroup.controllers
If this file is missing or empty, add systemd.unified_cgroup_hierarchy=1 to your kernel boot parameters in /etc/default/grub and run sudo update-grub.
Container Exits Immediately After Start
Cause: The CMD in your Containerfile launches a process that exits instantly or the application crashes on startup.
Fix: Check the container logs before assuming a Podman bug:
podman logs <container-name>
The actual error message almost always appears in the log output. A common culprit is a missing environment variable or a misconfigured entrypoint script.
Port Already in Use
Cause: Podman binds ports directly without a daemon intermediary, so conflicts surface immediately as hard errors rather than silent failures.
Fix: Find the process holding the port and stop it:
ss -tlnp | grep <port-number>
Then either stop the conflicting service or map your container to a different host port.
Rootless Container Cannot Bind Ports Below 1024
Cause: Linux restricts binding to ports under 1024 to the root user by default. Rootless Podman containers run as your regular user and hit this restriction.
Fix: Lower the unprivileged port start value temporarily:
sudo sysctl net.ipv4.ip_unprivileged_port_start=80
For a permanent fix, add net.ipv4.ip_unprivileged_port_start=80 to /etc/sysctl.d/99-podman.conf and run sudo sysctl --system. Alternatively, map the container to a port above 1024 (e.g., 8080:80) and use a reverse proxy like Nginx to handle traffic on port 80.
Error: “short-name resolution unqualified search is disabled”
Cause: Podman requires fully qualified image names by default on Ubuntu 26.04 because unqualified names could resolve to images from unintended registries.
Fix: Always prefix image names with the registry:
# Wrong
podman pull nginx
# Correct
podman pull docker.io/library/nginx:latest
Essential Podman Command Reference
These are the commands you will reach for most often when you install Podman on Ubuntu 26.04 LTS and start managing containers daily:
podman ps -a # List all containers including stopped
podman stop <name> # Stop a container gracefully (SIGTERM)
podman start <name> # Start a stopped container
podman restart <name> # Restart a container
podman rm <name> # Remove a stopped container
podman rm -f <name> # Force remove a running container
podman rmi <image> # Remove a local image
podman exec -it <name> bash # Open an interactive shell inside a container
podman inspect <name> # View full container metadata as JSON
podman stats # Live CPU, memory, and I/O per container
podman system prune -a # Remove all unused containers, images, volumes
podman generate kube <name> # Generate Kubernetes YAML from a running pod
podman auto-update # Pull latest images and restart Quadlet services
Congratulations! You have successfully installed Podman. Thanks for using this tutorial for installing Podman on the Ubuntu 26.04 LTS (Resolute Raccoon) system. For additional help or useful information, we recommend you check the official Podman website.