DEV Community

Ian Packard for Octasoft Ltd

Posted on • Originally published at wsl-ui.octasoft.co.uk

Running Podman on Windows with WSL: A Practical Guide

If you're developing on Windows but want to use Podman instead of Docker, you've probably discovered that running Podman natively in WSL isn't straightforward. After trying a few approaches, I settled on using Podman Desktop with WSL integration, which gives you the best of both worlds: a native Windows GUI and a seamless CLI experience from within WSL.

The Setup: Podman Desktop + WSL Remote Client

The key to this setup is using Podman Desktop on Windows, which runs Podman in its own WSL VM, and then connecting to it from your regular WSL distro using the Podman remote client. Here's how it works:

podman-desktop-with-remote-client-in-wsl/podman-wsl

Installing Podman Desktop

First, download and install Podman Desktop on Windows. During setup, it creates a dedicated WSL distribution (the "Podman Machine") and exposes a socket that other WSL distros can connect to.

After installation, make sure the Podman Machine is running—you'll see it in the Podman Desktop dashboard.

Installing the Podman Remote Client in WSL

Inside your WSL distribution (Ubuntu, Debian, etc.), you'll need the Podman remote client. Download it from the Podman releases page.

Tip: On the releases page, you'll need to expand the "Assets" section to find the download. Look for podman-remote-static-linux_amd64.tar.gz:

GitHub releases page showing the podman-remote downloads

# Download the static binary (check releases page for latest version)
curl -L https://github.com/containers/podman/releases/download/v5.7.1/podman-remote-static-linux_amd64.tar.gz -o /tmp/podman.tar.gz

# Extract and install
tar -xzf /tmp/podman.tar.gz -C /tmp
sudo mv /tmp/bin/podman-remote-static-linux_amd64 /usr/local/bin/podman
sudo chmod +x /usr/local/bin/podman

# Clean up
rm /tmp/podman.tar.gz
Enter fullscreen mode Exit fullscreen mode

Setting Up the Connection

The official way to connect is using podman system connection. First, find the available sockets:

find /mnt/wsl/podman-sockets/ -name '*.sock' 2>/dev/null
Enter fullscreen mode Exit fullscreen mode

You'll typically see paths like:

  • /mnt/wsl/podman-sockets/podman-machine-default/podman-root.sock (rootful)
  • /mnt/wsl/podman-sockets/podman-machine-default/podman-user.sock (rootless)

For most use cases, the rootful socket is more reliable:

podman system connection add --default podman-machine-default-root \
  unix:///mnt/wsl/podman-sockets/podman-machine-default/podman-root.sock
Enter fullscreen mode Exit fullscreen mode

Fixing Permissions

To communicate with the socket, your user needs write permissions. The socket is owned by group ID 10 (the wheel group on Fedora, which is what the Podman Machine runs):

sudo usermod --append --groups 10 $(whoami)
Enter fullscreen mode Exit fullscreen mode

Important: Log out and back into your WSL session for the group change to take effect.

Verify everything works:

podman version
podman ps
Enter fullscreen mode Exit fullscreen mode

Alternative: Environment Variables

If you prefer, you can skip podman system connection and use environment variables instead. Add these to your .bashrc or .zshrc:

export CONTAINER_HOST="unix:///mnt/wsl/podman-sockets/podman-machine-default/podman-root.sock"
export DOCKER_HOST="unix:///mnt/wsl/podman-sockets/podman-machine-default/podman-root.sock"
Enter fullscreen mode Exit fullscreen mode

The DOCKER_HOST variable is handy if you have tools that expect Docker but work with Podman's Docker-compatible API.

Running Your First Container

With the setup complete, let's verify everything works by running nginx:

# Pull and run nginx, mapping port 8080 on your host to port 80 in the container
podman run -d --name my-nginx -p 8080:80 nginx
Enter fullscreen mode Exit fullscreen mode

You should see Podman pull the nginx image and start the container:

Running podman to pull and start nginx

Check it's running:

podman ps
Enter fullscreen mode Exit fullscreen mode

Now open http://localhost:8080 in your browser—you should see the nginx welcome page.

The container is running inside the Podman Machine, but the port mapping makes it accessible from Windows. You'll also see the container in Podman Desktop's GUI, where you can view logs, stop/start it, or open a terminal:

Podman Desktop showing the running nginx container

When you're done:

# Stop and remove the container
podman stop my-nginx
podman rm my-nginx
Enter fullscreen mode Exit fullscreen mode

Common Challenges and Solutions

Socket Not Found

If you get errors about the socket not existing:

# Check if Podman Desktop is running and the machine is started
test -S /mnt/wsl/podman-sockets/podman-machine-default/podman-root.sock \
  && echo "Socket OK" \
  || echo "Socket missing - check Podman Desktop"
Enter fullscreen mode Exit fullscreen mode

Sometimes you need to restart the Podman Machine from Podman Desktop after a Windows or WSL restart.

The "/" Mount Warning

You might see this warning:

"/" is not a shared mount, this could cause issues or missing mounts with rootless containers
Enter fullscreen mode Exit fullscreen mode

This matters if you're bind mounting directories that contain other mounts. Fix it with:

sudo mount --make-rshared /
Enter fullscreen mode Exit fullscreen mode

You'll need to run this after each WSL restart, or add it to your .bashrc (with a check to avoid errors):

findmnt -n -o PROPAGATION / | grep -q shared || sudo mount --make-rshared /
Enter fullscreen mode Exit fullscreen mode

Volume Mounting: The Big Challenge

This is where things get tricky. When you run podman from your Ubuntu WSL distro, the actual container runs in the Podman Machine (a separate WSL distro). You're dealing with three different filesystems:

  1. Windows filesystem (C:\, D:\, etc.)
  2. Your WSL distro's filesystem (/home, /usr, etc.)
  3. Podman Machine's filesystem

The Problem: Paths that exist in your WSL distro don't automatically exist in the Podman Machine. This is a known limitation that the Podman team is aware of.

# This often fails - your WSL path doesn't exist in the Podman Machine
podman run -v ~/projects/myapp:/app alpine ls /app
Enter fullscreen mode Exit fullscreen mode

What works:

  1. Windows paths via /mnt: Paths under /mnt/c/, /mnt/d/ etc. are accessible from the Podman Machine because they're mounted from Windows:
# This works - Windows paths are shared across WSL distros
podman run -v /mnt/c/Users/YourName/projects:/app alpine ls /app
Enter fullscreen mode Exit fullscreen mode
  1. Named volumes for persistent data:
podman volume create mydata
podman run -v mydata:/data alpine sh -c "echo 'test' > /data/file.txt"
Enter fullscreen mode Exit fullscreen mode
  1. Copy files when you need them inside containers:
podman cp ./local-file.txt mycontainer:/destination/
podman cp mycontainer:/path/to/file ./local-destination/
Enter fullscreen mode Exit fullscreen mode

UID mismatch gotcha: If your WSL user has a UID other than 1000 (check with id), you may hit permission issues because the Podman Machine user is UID 1000. Using the rootful socket (podman-root.sock) instead of rootless usually avoids this.

The Bind Mount Workaround

If you really need to mount paths from your WSL filesystem (not just /mnt/c/), there's a workaround. The trick is to use /mnt/wsl/ as an intermediary—this directory is a shared mount namespace that both your WSL distro and the Podman Machine can see.

Here's the pattern:

# Get the real path of your source directory
source=$(realpath "${HOME}/.m2")

# Create a unique mount path using WSL's shared mount namespace
distro=${WSL_DISTRO_NAME}
source_sha256=$(echo -n "${source}" | sha256sum -z | head -c 64)
mount_path="/mnt/wsl/podman-bind-mounts/${distro}/${source_sha256}"

# Create the mount point and bind mount
sudo mkdir -p "${mount_path}"
sudo mount --bind "${source}" "${mount_path}" 2>/dev/null || true

# Now use the mounted path in podman
podman run -v "${mount_path}:/root/.m2" maven:latest mvn clean install
Enter fullscreen mode Exit fullscreen mode

Why does this work? The /mnt/wsl/ directory exists in a shared mount namespace accessible to all WSL distributions, including the Podman Machine. By bind-mounting your source directory there first, you're essentially making it visible to Podman.

The hash in the path keeps things tidy—you won't get collisions if you're mounting multiple directories, and you can easily create a helper function to automate this.

This is more fiddly than just using /mnt/c/ paths or named volumes, but it's the escape hatch when you need it. See GitHub issue #21813 for more discussion on this limitation.

Performance Note

Volume mounts through /mnt/c/ work but are noticeably slower than native Linux filesystem access. For performance-critical workloads, consider:

  • Working in named volumes
  • Copying files into the Podman Machine's filesystem
  • Using the Podman Machine directly instead of remoting from another distro

Tips for Daily Use

Keep Podman Desktop running. The Podman Machine needs to be running for the socket to be available. You can configure Podman Desktop to start with Windows.

Use aliases if you're coming from Docker:

alias docker=podman
alias docker-compose=podman-compose
Enter fullscreen mode Exit fullscreen mode

Check the socket if things stop working:

podman info >/dev/null 2>&1 && echo "Podman OK" || echo "Check Podman Desktop"
Enter fullscreen mode Exit fullscreen mode

Know where your data lives. Container images and volumes are stored in the Podman Machine, not your WSL distro. They persist across WSL restarts but are managed by Podman Desktop.

Conclusion

Running Podman on Windows with WSL takes some setup, but once configured it's a solid container development environment. The main gotcha is volume mounting—use Windows paths under /mnt/ or named volumes, and you'll avoid most headaches.

The combination of Podman Desktop's GUI and WSL UI access gives you flexibility. Just remember: when bind mounting, think about which filesystem the Podman Machine can actually see.

Further Reading

Top comments (0)