Podman is a daemonless, rootless container engine that serves as a drop-in replacement for Docker. It runs containers without a background service, which makes it lighter and more secure – especially useful on Windows where running a full Docker daemon inside WSL2 adds overhead. Podman 5.x brings full support for WSL2 on Windows 10 and 11, letting you build and run OCI-compliant containers from a Linux environment inside Windows.
This guide walks through installing Podman inside WSL2 on Windows, configuring registries and storage, running containers, building images, using Podman Desktop as a GUI, and setting up Podman Compose. Every command has been written for Ubuntu running inside WSL2, though the same steps work on Debian or Fedora WSL distributions with minor package manager changes.
Prerequisites
Before starting, make sure you have the following in place:
- Windows 10 version 2004 or later, or Windows 11 (any edition)
- Administrator access on the Windows machine
- At least 4 GB RAM (8 GB recommended for building images)
- Hardware virtualization enabled in BIOS/UEFI (Intel VT-x or AMD-V)
- Internet connection for downloading packages
Step 1: Enable WSL2 on Windows
WSL2 runs a real Linux kernel inside a lightweight virtual machine managed by Hyper-V. Open PowerShell as Administrator and enable the required Windows features.
Enable the Windows Subsystem for Linux feature:
dism.exe /online /enable-feature /featurename:Microsoft-Windows-Subsystem-Linux /all /norestart
Enable the Virtual Machine Platform, which WSL2 requires for its Hyper-V based backend:
dism.exe /online /enable-feature /featurename:VirtualMachinePlatform /all /norestart
Restart your machine after enabling both features. Once back in, open PowerShell as Administrator and set WSL2 as the default version:
wsl --set-default-version 2
Confirm WSL2 is active by checking the version:
wsl --version
The output should show WSL version 2.x with a Linux kernel version in the 5.15 or 6.x range:
WSL version: 2.4.13.0
Kernel version: 5.15.167.4-1
WSLg version: 1.0.65
If you see version 1 instead of 2, run wsl --update from PowerShell to pull the latest WSL2 kernel.
Step 2: Install a Linux Distribution in WSL2
WSL2 needs a Linux distribution to run. Ubuntu is the most common choice and has the best Podman package support. Install it from PowerShell:
wsl --install -d Ubuntu
This downloads and installs the latest Ubuntu LTS release. After installation completes, a terminal window opens and prompts you to create a UNIX username and password. Set these – they are your sudo credentials inside WSL2.
To see all installed distributions and confirm Ubuntu is running on WSL2:
wsl -l -v
You should see Ubuntu listed with VERSION set to 2:
NAME STATE VERSION
* Ubuntu Running 2
If the VERSION column shows 1, convert the distribution to WSL2:
wsl --set-version Ubuntu 2
Now launch your Ubuntu shell by typing wsl in PowerShell or opening Ubuntu from the Start menu. All remaining commands in this guide run inside the WSL2 Linux shell.
Step 3: Install Podman in WSL2
Inside your WSL2 Ubuntu shell, update the package index and install Podman. Ubuntu 24.04 and later include Podman in the default repositories.
sudo apt update
sudo apt install -y podman
After installation, verify the Podman version to confirm it installed correctly:
podman --version
The output shows the installed version:
podman version 4.9.3
The Ubuntu repository ships a stable but slightly older version. If you need the latest Podman 5.x release, install from the upstream Kubic/unstable repository instead:
sudo mkdir -p /etc/apt/keyrings
curl -fsSL "https://download.opensuse.org/repositories/devel:kubic:libcontainers:unstable/xUbuntu_$(lsb_release -rs)/Release.key" \
| gpg --dearmor \
| sudo tee /etc/apt/keyrings/devel_kubic_libcontainers_unstable.gpg > /dev/null
echo \
"deb [arch=$(dpkg --print-architecture) signed-by=/etc/apt/keyrings/devel_kubic_libcontainers_unstable.gpg] \
https://download.opensuse.org/repositories/devel:kubic:libcontainers:unstable/xUbuntu_$(lsb_release -rs)/ /" \
| sudo tee /etc/apt/sources.list.d/devel:kubic:libcontainers:unstable.list > /dev/null
sudo apt update
sudo apt install -y podman
Check the Podman info to confirm it can communicate with the container runtime:
podman info --format '{{.Host.OCIRuntime.Name}} {{.Host.OCIRuntime.Version}}'
This should return crun with its version, confirming the OCI runtime is functional:
crun 1.14.1
Step 4: Configure Podman Registries and Storage
Podman uses two main configuration files – registries.conf for container image sources and storage.conf for local storage settings. Configuring these properly avoids common “image not found” errors and storage permission issues in WSL2.
Configure Container Registries
The registries configuration tells Podman where to search for images when you pull without specifying a full registry path. Open the file:
sudo vi /etc/containers/registries.conf
Add the following configuration to set Docker Hub and Quay.io as unqualified search registries:
# Search these registries when no registry is specified in the image name
unqualified-search-registries = ["docker.io", "quay.io", "ghcr.io"]
# Docker Hub configuration
[[registry]]
prefix = "docker.io"
location = "docker.io"
With this configuration, running podman pull nginx searches Docker Hub first, then Quay.io, then GitHub Container Registry.
Configure Storage
Podman stores container images and layers locally. The default storage driver for rootless Podman is overlay, which works well in WSL2. Check the current storage configuration:
vi ~/.config/containers/storage.conf
Create the file if it does not exist and add these settings:
[storage]
driver = "overlay"
graphroot = "/home/$USER/.local/share/containers/storage"
runroot = "/run/user/$UID/containers"
[storage.options.overlay]
mount_program = "/usr/bin/fuse-overlayfs"
Install fuse-overlayfs if it is not already present – this provides a FUSE-based overlay filesystem that works reliably in rootless mode:
sudo apt install -y fuse-overlayfs
Verify the storage configuration by running a quick system check:
podman system info | head -20
Look for graphDriverName: overlay in the output, confirming the overlay driver is active.
Step 5: Run Containers with Podman on WSL2
With Podman installed and configured, pull and run your first container. The command syntax is identical to Docker, making migration straightforward.
Pull an Nginx image from Docker Hub:
podman pull docker.io/library/nginx:latest
Run the container in detached mode with port 8080 on the host mapped to port 80 inside the container:
podman run -d --name web -p 8080:80 nginx:latest
Confirm the container is running:
podman ps
The container list should show your Nginx service with port mapping active:
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
a1b2c3d4e5f6 docker.io/library/nginx:latest nginx -g daemon o... 5 seconds ago Up 5 seconds 0.0.0.0:8080->80/tcp web
Test the container from within WSL2 using curl:
curl -s http://localhost:8080 | head -5
You should see the Nginx welcome page HTML. WSL2 also forwards ports to the Windows host, so opening http://localhost:8080 in your Windows browser works too.
Stop and remove the container when finished:
podman stop web
podman rm web
Step 6: Build Container Images with Podman
Podman builds images from a Dockerfile (or Containerfile – Podman’s preferred name) using the same syntax as docker build. If you have existing Dockerfiles, they work with Podman without changes – the Buildah engine handles the actual build process under the hood.
Create a project directory and a simple Containerfile:
mkdir -p ~/myapp
vi ~/myapp/Containerfile
Add the following content to build a lightweight Python web application:
FROM docker.io/library/python:3.12-slim
WORKDIR /app
COPY app.py .
EXPOSE 5000
CMD ["python", "app.py"]
Create the application file:
vi ~/myapp/app.py
Add a minimal HTTP server:
from http.server import HTTPServer, BaseHTTPRequestHandler
class Handler(BaseHTTPRequestHandler):
def do_GET(self):
self.send_response(200)
self.send_header("Content-type", "text/plain")
self.end_headers()
self.wfile.write(b"Hello from Podman on WSL2\n")
HTTPServer(("0.0.0.0", 5000), Handler).serve_forever()
Build the image using podman build:
podman build -t myapp:latest ~/myapp/
After the build completes, list local images to confirm:
podman images
The output shows the newly built image along with any base images pulled during the build:
REPOSITORY TAG IMAGE ID CREATED SIZE
localhost/myapp latest f1e2d3c4b5a6 10 seconds ago 155 MB
docker.io/library/python 3.12-slim a9b8c7d6e5f4 2 weeks ago 149 MB
Run and test the custom image:
podman run -d --name myapp -p 5000:5000 myapp:latest
curl http://localhost:5000
You should see Hello from Podman on WSL2 in the response.
Step 7: Install Podman Desktop on Windows
Podman Desktop is a graphical application for managing containers, images, pods, and volumes from Windows. It connects to the Podman engine running inside WSL2 and provides a visual interface similar to Docker Desktop – but without the licensing restrictions.
Download Podman Desktop from the official downloads page. Run the installer – it detects your existing WSL2 Podman installation automatically.
Alternatively, install via Windows Package Manager from PowerShell:
winget install RedHat.Podman-Desktop
After launching Podman Desktop, it connects to the Podman socket inside WSL2. You can:
- Pull and manage images from a visual catalog
- Start, stop, and inspect running containers
- View container logs in real time
- Open a terminal shell inside any running container
- Manage pods (groups of containers sharing a network namespace)
- Build images from Containerfiles with a visual progress view
Podman Desktop also supports extensions for Kubernetes, Compose, and Kind clusters – making it a full container development environment on Windows.
Step 8: Podman vs Docker on Windows – Key Differences
Both Podman and Docker run Linux containers on Windows through WSL2, but they differ in architecture and workflow. Understanding these differences helps you decide which tool fits your environment.
Daemonless architecture – Docker requires a background daemon (dockerd) that all client commands talk to. Podman has no daemon – each podman command forks its own process, runs the operation, and exits. This means no single point of failure and lower resource usage when idle.
Rootless by default – Podman runs containers as your regular user without needing root privileges. Docker on WSL2 typically requires adding your user to the docker group, which effectively grants root-equivalent access to the Docker socket. With Podman, containers run in your user namespace with no privilege escalation.
Licensing – Docker Desktop requires a paid subscription for companies with more than 250 employees or over $10 million in revenue. Podman and Podman Desktop are fully open source under the Apache 2.0 license with no commercial restrictions.
Pods – Podman natively supports pods – groups of containers that share networking and storage, matching the Kubernetes pod concept. Docker has no native pod support. If you work with Kubernetes, this makes Podman a more natural local development tool.
Compatibility – Podman is command-compatible with Docker. You can alias docker to podman and most workflows continue unchanged. Dockerfiles, Compose files, and registry operations all work the same way.
Step 9: Use Podman Compose for Multi-Container Applications
Podman Compose reads standard docker-compose.yml files and creates containers using Podman instead of Docker. This lets you run existing Compose-based applications without modification.
Install Podman Compose via pip inside WSL2:
sudo apt install -y python3-pip
pip3 install podman-compose
Verify the installation:
podman-compose --version
Create a sample multi-container application with a web server and Redis backend. Set up a project directory:
mkdir -p ~/compose-demo
vi ~/compose-demo/docker-compose.yml
Add the following Compose configuration:
version: "3.8"
services:
web:
image: docker.io/library/nginx:latest
ports:
- "8080:80"
depends_on:
- cache
cache:
image: docker.io/library/redis:7
ports:
- "6379:6379"
Start the stack in detached mode:
cd ~/compose-demo
podman-compose up -d
Check running containers to confirm both services are up:
podman-compose ps
Both the Nginx web server and Redis cache should show as running. To bring down the stack and remove the containers:
podman-compose down
If you already have Docker Compose projects, they work with Podman Compose without changes to the YAML files. You can also use the systemd integration to run Podman containers as services that start automatically.
Step 10: Rootless Networking and Port Mapping
One of Podman’s strengths is running containers entirely as a non-root user. However, rootless networking has a few WSL2-specific behaviors worth understanding.
Port Mapping in Rootless Mode
Rootless Podman uses slirp4netns or pasta for user-mode networking. Ports above 1024 work without any extra configuration:
podman run -d --name test-web -p 8080:80 nginx:latest
To bind to ports below 1024 (like port 80 or 443) without running as root, lower the unprivileged port start value:
sudo sysctl -w net.ipv4.ip_unprivileged_port_start=80
Make the setting persistent across WSL2 restarts:
echo "net.ipv4.ip_unprivileged_port_start=80" | sudo tee -a /etc/sysctl.conf
sudo sysctl -p
WSL2 Port Forwarding to Windows
WSL2 automatically forwards ports from the Linux environment to Windows localhost. When you map port 8080 inside WSL2, it is accessible at http://localhost:8080 from Windows browsers and applications.
To access containers from other machines on your network, you need to forward the port through Windows Firewall. Run this from an elevated PowerShell prompt:
netsh interface portproxy add v4tov4 listenport=8080 listenaddress=0.0.0.0 connectport=8080 connectaddress=localhost
Then allow the port through Windows Firewall:
netsh advfirewall firewall add rule name="WSL2 Podman 8080" dir=in action=allow protocol=TCP localport=8080
Networking Between Containers
Containers on the same Podman network can reach each other by name. Create a custom network and attach containers to it:
podman network create mynet
podman run -d --name backend --network mynet redis:7
podman run -d --name frontend --network mynet -p 8080:80 nginx:latest
The frontend container can now resolve the hostname backend to reach the Redis container. Verify connectivity:
podman exec frontend ping -c 2 backend
For more advanced container orchestration, consider deploying your workloads on Kubernetes using Kompose to convert your Compose files to Kubernetes manifests.
Podman vs Docker Command Reference
Podman is a drop-in replacement for Docker at the CLI level. The following table maps common Docker commands to their Podman equivalents – in most cases, the syntax is identical.
| Docker Command | Podman Equivalent |
|---|---|
docker pull nginx | podman pull nginx |
docker run -d nginx | podman run -d nginx |
docker build -t myapp . | podman build -t myapp . |
docker ps | podman ps |
docker images | podman images |
docker logs container | podman logs container |
docker exec -it container bash | podman exec -it container bash |
docker-compose up | podman-compose up |
docker network create net | podman network create net |
docker volume create vol | podman volume create vol |
| N/A (no native equivalent) | podman pod create |
docker system prune | podman system prune |
You can also create a shell alias to use Podman as a transparent Docker replacement. Add this line to your ~/.bashrc in WSL2:
echo 'alias docker=podman' >> ~/.bashrc
source ~/.bashrc
After this, all docker commands route through Podman automatically. Existing scripts and muscle memory continue working without modification.
Conclusion
Podman running inside WSL2 gives you a fully functional, rootless container engine on Windows with no daemon overhead and no licensing fees. You can build images, run multi-container stacks with Podman Compose, and manage everything through Podman Desktop’s GUI – all while maintaining drop-in compatibility with Docker commands and Dockerfiles.
For production workloads, consider adding persistent volume mounts for data that needs to survive container restarts, configuring automatic container startup with systemd user services inside WSL2, and setting up a private registry if you build custom images regularly. Review the official Podman documentation for advanced configuration options including rootless networking tuning and SELinux/seccomp profiles.