How to Install Podman on Ubuntu: Rootless Container Alternative to Docker

Podman is a daemonless container engine that runs OCI containers without a long-lived root process. Each container is started as a regular user-owned process, which removes the privileged daemon that Docker relies on and makes containers safer to run on shared servers. The command-line surface mirrors Docker almost exactly, so most Dockerfiles, image references, and docker run patterns work with little to no change.
This guide explains how to install Podman on Ubuntu, configure rootless mode, run your first container, and use Podman as a drop-in replacement for the Docker CLI.
Quick Reference
For a printable quick reference, see the Podman cheatsheet .
| Task | Command |
|---|---|
| Install Podman | sudo apt install podman |
| Run a container | podman run -d --name web -p 8080:80 nginx |
| List containers | podman ps -a |
| Build an image | podman build -t myimage . |
| List images | podman images |
| Pull an image | podman pull alpine:latest |
| Stop and remove | podman rm -f web |
| Inspect rootless setup | podman info |
Install Podman
Podman has been part of the Ubuntu universe repository since 20.10, so on every supported release you can install it through apt without adding a third-party PPA.
Update the package index, then install:
sudo apt update
sudo apt install podmanConfirm the version:
podman --versionpodman version 5.7.0Ubuntu 26.04 ships Podman 5.7 from the universe repository. Ubuntu 24.04 ships the 4.9 series, while Ubuntu 22.04 ships the 3.4 series, so the exact version depends on the Ubuntu release you are using.
Verify the Rootless Setup
Podman supports both root and rootless modes, and the rootless mode is the one most users want. Run podman info as your regular user and look for rootless: true:
podman info | head -20host:
arch: amd64
cgroupManager: systemd
...
security:
rootless: trueTwo pieces have to be in place for rootless containers to work: subordinate UID/GID mappings, and a user namespace. Ubuntu sets both up automatically on first run, but you can confirm with:
cat /etc/subuid /etc/subgidsara:100000:65536
sara:100000:65536Each user gets a range of 65,536 subordinate UIDs and GIDs that Podman uses to map container processes to non-overlapping host IDs. If the file is missing your user, add an entry with sudo usermod --add-subuids 100000-165535 --add-subgids 100000-165535 sara and run podman system migrate to apply the change.
Run Your First Container
Pull and run an Nginx container in detached mode, exposing port 8080 on the host:
podman run -d --name web -p 8080:80 nginxResolved "nginx" as an alias (/etc/containers/registries.conf.d/shortnames.conf)
Trying to pull docker.io/library/nginx:latest...
Getting image source signatures
Copying blob sha256:...
Writing manifest to image destination
Storing signatures
2b9bd4e1f3...Check that the container is running:
podman psCONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
2b9bd4e1f3a8 docker.io/library/nginx:latest nginx -g daemon o... 10 seconds ago Up 10 seconds 0.0.0.0:8080->80/tcp webHit the published port from the host:
curl -I http://localhost:8080HTTP/1.1 200 OK
Server: nginx/1.27.4The response confirms that the user-mode network stack forwarded the request into the container correctly. Stop and remove the container with:
podman rm -f webConfigure Registries
By default Podman searches a configured list of registries when you run podman pull nginx (without a registry prefix). The list lives in /etc/containers/registries.conf. To prefer Docker Hub, edit the file:
sudo nano /etc/containers/registries.confSet the unqualified-search registries:
unqualified-search-registries = ["docker.io", "quay.io"]Save and exit. From now on podman pull alpine resolves to docker.io/library/alpine:latest, which matches Docker’s default behavior. Save yourself confusion by always pulling with the full reference (podman pull docker.io/library/alpine) in scripts and CI pipelines.
Use Podman as a Docker Replacement
If you already have shell history, Makefiles, or scripts that call docker, install the alias package and keep them working:
sudo apt install podman-dockerThe package adds a /usr/bin/docker symlink that points to podman, plus a stub that suppresses the daemon-not-running warning. Test it:
docker run --rm hello-worldHello from Docker!Behind the scenes, docker run invoked podman run. Most everyday commands (build, pull, push, images, ps, logs, exec) work identically. The differences show up around Docker Compose and the daemon socket; Podman 4 ships its own socket that Docker Compose can target by setting DOCKER_HOST.
Build an Image with a Dockerfile
Podman builds OCI images from a standard Dockerfile, no changes required. Create a small Flask app to demonstrate:
mkdir hello-podman && cd hello-podman
nano app.pyfrom flask import Flask
app = Flask(__name__)
@app.route("/")
def index():
return "Hello from Podman!"
if __name__ == "__main__":
app.run(host="0.0.0.0", port=5000)Write the Dockerfile:
FROM python:3.12-slim
WORKDIR /app
RUN pip install --no-cache-dir flask
COPY app.py .
EXPOSE 5000
CMD ["python", "app.py"]Build the image:
podman build -t hello-podman .STEP 1/6: FROM python:3.12-slim
STEP 2/6: WORKDIR /app
...
Successfully tagged localhost/hello-podman:latestRun a container from the new image:
podman run -d --name hello -p 5000:5000 hello-podman
curl http://localhost:5000Hello from Podman!The image and container both live in the user’s storage (~/.local/share/containers), so no sudo is involved at any step.
Run Pods of Containers
The name “Podman” comes from its support for Kubernetes-style pods: groups of containers that share a network namespace. Create an empty pod, then add containers to it:
podman pod create --name webapp -p 8080:80
podman run -d --pod webapp --name redis redis:7
podman run -d --pod webapp --name nginx nginxInside the pod, nginx can reach Redis at localhost:6379 because they share the network namespace. List pods with:
podman pod psPOD ID NAME STATUS CREATED INFRA ID # OF CONTAINERS
8f4d7b8c0e1f webapp Running 20 seconds ago c2a8f9b1d3e4 3The count of three includes an infra container that holds the shared namespaces.
Run Podman as a systemd Service
To start a container at boot in rootless mode, use a Quadlet container unit. Quadlet is Podman’s current systemd integration method and keeps the container definition in a small, readable file.
mkdir -p ~/.config/containers/systemd
nano ~/.config/containers/systemd/web.containerAdd the container definition:
[Unit]
Description=Rootless Nginx container
[Container]
Image=docker.io/library/nginx:latest
ContainerName=web
PublishPort=8080:80
[Service]
Restart=always
[Install]
WantedBy=default.targetReload the user systemd manager, then start the generated service:
systemctl --user daemon-reload
systemctl --user start web.serviceEnable lingering so the user services keep running after logout:
sudo loginctl enable-linger saraThe [Install] section tells the Podman systemd generator to attach the service to the user’s default target. The container now starts without root or a system-wide daemon.
Troubleshooting
Error: short-name "nginx" did not resolve to an alias
The unqualified-search-registries list is empty. Edit /etc/containers/registries.conf and add at least docker.io, or pull with the full reference (podman pull docker.io/library/nginx).
ERRO[0000] cannot find UID/GID for user
The current user has no entry in /etc/subuid or /etc/subgid. Run sudo usermod --add-subuids 100000-165535 --add-subgids 100000-165535 $USER, then podman system migrate.
Ports under 1024 refuse to bind in rootless mode
The kernel restricts low ports for non-root users. Either publish to a high port (-p 8080:80), or allow your user to bind low ports with sudo sysctl net.ipv4.ip_unprivileged_port_start=80.
FAQ
Is Podman a drop-in Docker replacement?
For everyday run, build, pull, push, and exec workflows, yes. Compose and the long-lived socket need extra setup. Most CI jobs only need the CLI and switch over without changes.
Does Podman work with Docker Compose?
Yes. Start the Podman socket with systemctl --user enable --now podman.socket, export DOCKER_HOST=unix://$XDG_RUNTIME_DIR/podman/podman.sock, and run docker compose up.
Are Podman images compatible with Docker?
Yes. Both produce OCI-compliant images, so an image built with podman build runs unchanged under Docker, and vice versa.
Conclusion
Podman gives you the Docker workflow without the daemon and without root, which is often what you want on a multi-user server or a developer workstation. Install it from apt, alias docker if you have existing scripts, and the rest of the CLI feels familiar.
For follow-up reading, see our guides on installing Docker on Ubuntu 26.04 and building Docker images with a Dockerfile .
Linuxize Weekly Newsletter
A quick weekly roundup of new tutorials, news, and tips.
About the authors

Dejan Panovski
Dejan Panovski is the founder of Linuxize, an RHCSA-certified Linux system administrator and DevOps engineer based in Skopje, Macedonia. Author of 800+ Linux tutorials with 20+ years of experience turning complex Linux tasks into clear, reliable guides.
View author page