DEV Community

Utkarsh Shigihalli
Utkarsh Shigihalli

Posted on

Setting Up Podman Desktop So the Same Containers Work on Both Windows and WSL2

The main goal of this setup is simple: run a container once, and access that exact same container from both PowerShell and WSL2, not two separate copies running in isolation. There are some genuine benefits with this setup in my opinion.

  1. Work across both shells naturally: I am on WSL for almost everything but occasionally I also use PowerShell for Windows side tasks. Having one engine means I never get stuck wondering “which shell did I start this container in?”
  2. Avoiding duplicate engine wastes resources: If WSL runs it own local rootless Podman and Windows runs Podman Desktop’s VM separately, you would have 2 entirely separate container runtime wasting CPU/RAM with no containers visible to each other.
  3. One source of truth for debugging: If a container from WSL is having issues, you can just check podman logs or podman inspect from PowerShell (or vice versa) without switching contexts.
  4. Consistent networking port access: Since its the same container, ports you map are reachable from localhost in your Windows browser and from WSL’s network stack.

Podman Desktop makes this possible because it runs a single Linux VM (podman-machine-default) that acts as your container engine. Both PowerShell and WSL2 can talk to that same machine over SSH, so a container you start in one place is immediately visible, manageable, and reachable from the other. Start a container from WSL, inspect it from PowerShell, curl it from WSL again, all pointing at the same running process.

This guide covers the setup end to end, including the gotchas that most commonly break it.

Podman Desktop

The Connection Model

Podman Desktop exposes its VM over SSH, and any CLI (Windows or WSL) is just a client dialing in. You can see this directly:

$ podman system connection list
Name                         URI                                                          Default
podman-machine-default       ssh://user@127.0.0.1:52464/run/user/1000/podman/podman.sock  false
podman-machine-default-root  ssh://root@127.0.0.1:52464/run/podman/podman.sock            true
Enter fullscreen mode Exit fullscreen mode

Two connections always exist for one machine:

  1. Rootless (user@...): containers run under an unprivileged user inside the VM via Linux user namespaces
  2. Rootful (root@...): containers run as root inside the VM

Pick one and keep both sides pointed at it consistently. That consistency is what makes “same container, both sides” actually work.

Rootless is the sensible default for local development: file ownership on bind mounts maps more predictably back to your actual user, and containers are better isolated. You only need rootful for binding to privileged ports (below 1024) or specific low-level system capabilities, which is rare for everyday work.

Gotcha #1: The Machine Itself Needs to Be Rootless, Not Just the Connection

Setting the rootless connection as default via CLI…

$ podman system connection default podman-machine-default
Enter fullscreen mode Exit fullscreen mode

…can look like it worked, but Podman Desktop may keep popping up this dialog:

Rootful Podman Machine ‘podman-machine-default’ does not match default connection. This will cause podman CLI errors while trying to connect to ‘podman-machine-default’. Do you want to update the default connection?

Clicking “Yes” here silently flips your CLI default back to rootful, undoing your change. That’s because the dialog is really telling you the machine booted in rootful mode, and setting the connection default alone doesn’t match that. Fighting it at the connection level is a losing battle; it will keep reverting.

The real fix is at the machine level:

podman machine stop
podman machine set --rootful=false podman-machine-default
podman machine start
Enter fullscreen mode Exit fullscreen mode

Confirm it worked by checking Podman Desktop’s UI. It should explicitly show:

Podman Rootless VM

Once the machine itself is rootless, the mismatch dialog stops appearing for good, and podman system connection list stays stable with rootless as default.

Note: stopping the machine kills any running containers. You will need to restart or recreate them afterward.

Gotcha #2: WSL’s Podman CLI Doesn’t Know About the Windows Machine by Default

Installing podman inside WSL via apt gives you a separate, local installation. It has no idea the Windows-side machine exists. To make it a client of that same machine:

  1. Install the podman CLI in WSL:
sudo apt update
sudo apt install -y podman
Enter fullscreen mode Exit fullscreen mode
  1. Add a connection pointing at the Windows machine, using the exact URI and port from PowerShell’s podman system connection list, with the identity path converted to WSL's /mnt/c/... mount form:
podman system connection add podman-machine-default \
  --identity "/mnt/c/Users/<your-username>/.local/share/containers/podman/machine/machine" \
  ssh://user@127.0.0.1:<port>/run/user/1000/podman/podman.sock

podman system connection default podman-machine-default
Enter fullscreen mode Exit fullscreen mode
  1. Force WSL’s podman into remote-client mode permanently. Without this, even with a connection added and set default, WSL’s local podman binary tries to run containers locally first, which is what throws:
Error: command required for rootless mode with multiple IDs: exec: "newuidmap": executable file not found in $PATH
Enter fullscreen mode Exit fullscreen mode

Fix it by setting remote mode in config:

mkdir -p ~/.config/containers
cat >> ~/.config/containers/containers.conf << 'EOF'
[engine]
remote = true
EOF
Enter fullscreen mode Exit fullscreen mode
  1. Verify
podman ps -a
podman run --rm quay.io/podman/hello:latest
Enter fullscreen mode Exit fullscreen mode

Gotcha #3: The SSH Port Changes on Every Machine Restart

The port Podman Desktop assigns (52464, 59044, and so on) is dynamic and changes on every machine restart: reboot, manual podman machine stop/start, Windows update, and so on. When that happens, WSL's connection (which has the old port hardcoded) silently breaks:

Error: unable to connect to Podman socket: failed to connect: dial tcp 127.0.0.1:52464: connect: connection refused
Enter fullscreen mode Exit fullscreen mode

Fix: re-sync WSL’s connection with the current port whenever the machine restarts:

podman system connection remove podman-machine-default

podman system connection add podman-machine-default \
  --identity "/mnt/c/Users/<your-username>/.local/share/containers/podman/machine/machine" \
  ssh://user@127.0.0.1:<current-port-from-powershell>/run/user/1000/podman/podman.sock

podman system connection default podman-machine-default
Enter fullscreen mode Exit fullscreen mode

Get the current port from PowerShell first:

podman system connection list
Enter fullscreen mode Exit fullscreen mode

Verifying It Works End-to-End

Once both sides point at the same rootless machine, confirm it properly:

  1. Start a persistent container from either side:
podman run -d --name test-nginx -p 8080:80 docker.io/library/nginx:latest
Enter fullscreen mode Exit fullscreen mode
  1. Check it shows up identically from both CLIs:
podman ps
Enter fullscreen mode Exit fullscreen mode
podman ps
Enter fullscreen mode Exit fullscreen mode

Both should list the exact same container ID.

Podman Container on Windows

Podman Container on WSL

  1. Confirm browser access via WSL2’s automatic localhost forwarding: Open http://localhost:8080 in your Windows browser. You should see the nginx welcome page. This works regardless of which side started the container, since WSL2 forwards ports to the Windows host automatically.

  2. Or check from the command line:

curl http://localhost:8080
Enter fullscreen mode Exit fullscreen mode

Conclusion

In short: containers.conf with remote = true isn't optional here — without it, WSL's local podman binary will always try to spin up its own local engine first, regardless of what connection you've set as default. It's the one setting that actually forces WSL into "client of the Windows machine" mode rather than "separate engine that happens to have a saved connection."

Top comments (0)