How To

Run Podman on Windows with WSL2

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.

Original content from computingforgeeks.com - post 60160

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 CommandPodman Equivalent
docker pull nginxpodman pull nginx
docker run -d nginxpodman run -d nginx
docker build -t myapp .podman build -t myapp .
docker pspodman ps
docker imagespodman images
docker logs containerpodman logs container
docker exec -it container bashpodman exec -it container bash
docker-compose uppodman-compose up
docker network create netpodman network create net
docker volume create volpodman volume create vol
N/A (no native equivalent)podman pod create
docker system prunepodman 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.

Related Articles

Containers Install MicroK8s Kubernetes Cluster on Linux Mint Cloud How To Run Flatcar Container Linux on OpenStack Containers How To Install and Use Headlamp Kubernetes Web UI Storage How To add FTP Site on Windows Server 2019

Leave a Comment

Press ESC to close