Recent Posts
Archives

Posts Tagged ‘WSL’

PostHeaderIcon Windows IP Helper Service (IPHLPSVC): Why Network Pros Restart It for WSL 2

The IP Helper service, formally known as IPHLPSVC, is a silent, critical workhorse within the Windows operating system. While it maintains the integrity of fundamental network configurations, it is often the first component targeted by network administrators and developers when troubleshooting complex connectivity issues, particularly those involving virtual environments like WSL 2 (Windows Subsystem for Linux 2). Understanding its functions and its potential for interference is key to efficient network diagnostics.


What is the IP Helper Service?

The IP Helper service is a core Windows component responsible for managing network configuration and ensuring seamless connectivity across various network protocols. It serves several vital functions related to the Internet Protocol (IP) networking stack:

  • IPv6 Transition Technologies: The service is primarily responsible for managing and tunneling IPv6 traffic across IPv4 networks. This is achieved through mechanisms such as ISATAP, Teredo, and 6to4.
  • Local Port Control: It provides essential notification support for changes occurring in network interfaces. Furthermore, it manages the retrieval and configuration of localized network information.
  • Network Configuration Management: IPHLPSVC assists in the retrieval and modification of core network configuration settings on the local computer.

The WSL 2 Connection: Why IP Helper Causes Headaches

While essential for Windows, the deep integration of IPHLPSVC into the network stack means it can cause intermittent conflicts with virtualized environments like WSL 2. Developers frequently target this service because it often interferes with virtual networking components, leading to issues that prevent containers or services from being reached.

1. Conflict with NAT and Virtual Routing 💻

WSL 2 runs its Linux distribution inside a lightweight virtual machine (VM). Windows creates a virtual network switch, relying on Network Address Translation (NAT) to provide the VM with internet access. IPHLPSVC manages core components involved in establishing these virtual network interfaces and their NAT configurations. If the service becomes unstable or misconfigures a component, it can disrupt the flow of data across the virtual network bridge.

2. Interference from IPv6 Tunneling ⛔

The service’s management of IPv6 transition technologies (Teredo, 6to4, etc.) is a frequent source of conflict. These aggressive tunneling mechanisms can introduce subtle routing conflicts that undermine the stable, direct routing required by the WSL VM’s network adapter. The result is often connection instability or intermittent routing failures for applications running within the Linux instance (e.g., Docker or Nginx).

3. Resolving Stuck Ports and Port Forwarding Glitches 🛠️

When a service runs inside WSL 2, Windows automatically handles the port forwarding necessary to expose Linux services (which live on an ephemeral virtual IP) to the Windows host. This process can occasionally glitch, resulting in a port that appears blocked or unavailable. Restarting the IP Helper service is a common diagnostic and remedial step because it forces a reset of these core networking components. By doing so, it compels Windows to re-evaluate and re-initialize local port settings and network configuration, often clearing the blockage and restoring access to the virtualized services.


Troubleshooting: Diagnosing and Fixing IPHLPSVC Conflicts

When facing connectivity issues, especially after using WSL or Docker, troubleshooting often involves systematically resetting the network components managed by the IP Helper service.

1. Inspection Tools (Run as Administrator)

Use these native Windows tools to diagnose potential conflicts:

  • netsh: The primary command-line tool for inspecting and configuring IPv6 transition tunnels and port forwarding rules. Use netsh interface Teredo show state to check Teredo’s operational status.
  • netstat -ano: Used to inspect active ports and determine if a service (or a stuck process) is holding a port hostage.
  • ipconfig /all: Essential for verifying the current IPv4/IPv6 addresses and adapter statuses before and after applying fixes.

2. Fixing Persistent Conflicts (Disabling Tunneling)

If you suspect the IPv6 transition technologies are causing instability, disabling them often provides the greatest stability, especially if you do not rely on native IPv6 connectivity.

Run these commands in an Elevated Command Prompt (Administrator):

REM --- Disable Teredo Protocol ---
netsh interface Teredo set state disabled

REM --- Disable 6to4 Protocol ---
netsh interface ipv6 6to4 set state disabled

REM --- Restart IPHLPSVC to apply tunnel changes ---
net stop iphlpsvc
net start iphlpsvc

3. Fixing Port Glitches (Restarting/Resetting)

For port-forwarding glitches or general networking instability, a full stack reset is the last resort.

  • Immediate Fix (Service Restart): If a service running in WSL is unreachable, a simple restart of IPHLPSVC often clears the NAT table entries and port locks:
    Restart-Service iphlpsvc
  • Aggressive Fix (Stack Reset): To fix deeper corruption managed by the IP Helper service, reset the TCP/IP stack:
    netsh winsock reset
    netsh int ip reset
    ipconfig /flushdns

    ❗ Mandatory Step: A full system reboot is required after running netsh int ip reset to finalize the changes and ensure a clean network stack initialization.


Summary: A Key Diagnostic Tool

Restarting the IP Helper service is an efficient first-line diagnostic technique. It provides a means to reset core Windows networking behavior and virtual connectivity components without resorting to a time-consuming full operating system reboot, making it an invaluable step in troubleshooting complex, modern development environments.

PostHeaderIcon ⚙️ How to Fix Missing User Setup in Ubuntu 22 on WSL2 (Windows 11)

TL;DR:

If you installed Ubuntu 22.04 on Windows 11 using WSL2 and the system never prompted you to create a user, it means the initial setup script did not run correctly. You are now logging in as root directly. To fix this, manually create your user, grant it sudo rights, and set it as the default login account:

sudo adduser jlalou
sudo usermod -aG sudo jlalou
ubuntu2204.exe config --default-user jlalou

After restarting WSL, you’ll log in as a normal user with administrator privileges.

🧩 Understanding the Issue

When you install Ubuntu from the Microsoft Store or via the wsl --install command, WSL normally runs a first-launch configuration script. That script asks for a username, sets a password, adds the user to the sudo group, and makes it the default account for future sessions.

If that welcome prompt never appeared, Ubuntu is skipping its initialization phase. This often happens when:

  • The first start was interrupted or closed prematurely.
  • The distribution was imported manually with wsl --import.
  • You started WSL as root before the setup script ran.

In this case, WSL falls back to the default root account, leaving no regular user configured.

✅ Step-by-Step Solution

1️⃣ Create Your User Manually

Launch your Ubuntu terminal (it will open as root), then create your desired user account:

adduser jlalou

Enter a password when prompted, and confirm the optional user details. Next, give this new account administrative privileges:

usermod -aG sudo jlalou

You can confirm the membership with:

grep jlalou /etc/group

If you see sudo listed among the groups, the user has been successfully added.

2️⃣ Make This User the Default Login Account

List your installed distributions:

wsl -l -v

You’ll see something like:

NAME            STATE           VERSION
* Ubuntu-22.04   Running         2

In PowerShell (or Command Prompt), set your new user as the default:

ubuntu2204.exe config --default-user jlalou

(The command name may vary slightly—use Get-Command *ubuntu* in PowerShell if you’re unsure.)

Close all Ubuntu windows and reopen WSL. You should now log in automatically as jlalou.

3️⃣ Verify Everything Works

Once inside the shell, check your identity and privileges:

whoami
# Expected output: jlalou

sudo ls /root
# Should prompt for your password and succeed

If both commands work, your configuration is complete.

🔁 Optional: Trigger the Initial Setup from Scratch

If you prefer to start over and allow Ubuntu’s built-in setup wizard to handle everything automatically, simply unregister and reinstall the distribution:

wsl --unregister Ubuntu-22.04
wsl --install -d Ubuntu-22.04

Upon first launch, Ubuntu will display:

Installing, this may take a few minutes...
Please create a default UNIX user account.

From there you can define your username and password normally.

🧠 Why This Happens

WSL integrates tightly with Windows, but when the initialization script fails, it bypasses Ubuntu’s user-creation process. This can occur when the image is imported, cloned, or restored without the metadata WSL expects. As a result, Ubuntu runs entirely as root, skipping all onboarding logic.

While this is convenient for testing, it’s not secure or practical for daily use. Running as a dedicated user with sudo access ensures safer file permissions, a more predictable environment, and compatibility with Ubuntu’s standard management tools.

🧾 Summary Table

Goal Command
Create user adduser jlalou
Grant sudo rights usermod -aG sudo jlalou
Set as default login ubuntu2204.exe config --default-user jlalou
Verify identity whoami / sudo echo ok

🚀 Conclusion

Missing the initial user setup prompt in Ubuntu 22 under WSL2 can be confusing, but it’s easily corrected. Creating a dedicated user and assigning sudo privileges restores the intended WSL experience—secure, organized, and fully functional. Once configured, you can enjoy seamless integration between Windows 11 and Ubuntu, with the flexibility and power of both operating systems at your fingertips.

PostHeaderIcon Fixing the “Failed to Setup IP tables” Error in Docker on WSL2

TL;DR:
If you see this error when running Docker on Windows Subsystem for Linux (WSL2):

ERROR: Failed to Setup IP tables: Unable to enable SKIP DNAT rule:
(iptables failed: iptables --wait -t nat -I DOCKER -i br-xxxx -j RETURN:
iptables: No chain/target/match by that name. (exit status 1))

👉 The cause is usually that your system is using the nftables backend for iptables, but Docker expects the legacy backend.
Switching iptables to legacy mode and restarting Docker fixes it:

sudo update-alternatives --set iptables /usr/sbin/iptables-legacy
sudo update-alternatives --set ip6tables /usr/sbin/ip6tables-legacy

Then restart Docker and verify:

sudo iptables -t nat -L

You should now see the DOCKER chain listed. ✅


🔍 Understanding the Problem

When Docker starts, it configures internal network bridges using iptables.
If it cannot find or manipulate its DOCKER chain, you’ll see this “Failed to Setup IP tables” error.
This problem often occurs in WSL2 environments, where the Linux kernel uses the newer nftables system by default, while Docker still relies on the legacy iptables interface.

In short:

  • iptables-nft (default in modern WSL2) ≠ iptables-legacy (expected by Docker)
  • The mismatch causes Docker to fail to configure NAT and bridge rules

⚙️ Step-by-Step Fix

1️⃣ Check which iptables backend you’re using

sudo iptables --version
sudo update-alternatives --display iptables

If you see something like iptables v1.8.x (nf_tables), you’re using nftables.

2️⃣ Switch to legacy mode

sudo update-alternatives --set iptables /usr/sbin/iptables-legacy
sudo update-alternatives --set ip6tables /usr/sbin/ip6tables-legacy

Confirm the change:

sudo iptables --version

Now it should say (legacy).

3️⃣ Restart Docker

If you’re using Docker Desktop for Windows:

wsl --shutdown
net stop com.docker.service
net start com.docker.service

or simply quit and reopen Docker Desktop.

If you’re running Docker Engine inside WSL:

sudo service docker restart

4️⃣ Verify the fix

sudo iptables -t nat -L

You should now see the DOCKER chain among the NAT rules:

Chain DOCKER (2 references)
target     prot opt source               destination
RETURN     all  --  anywhere             anywhere

If it appears — congratulations 🎉 — your Docker networking is fixed!


🧠 Extra Troubleshooting Tips

  • If the error persists, flush and rebuild the NAT table:
    sudo service docker stop
    sudo iptables -t nat -F
    sudo iptables -t nat -X
    sudo service docker start
    
  • Check kernel modules (for completeness):
    lsmod | grep iptable
    sudo modprobe iptable_nat
    
  • Keep Docker Desktop and WSL2 kernel up to date — many network issues are fixed in newer builds.

✅ Summary

Step Command Goal
Check backend sudo iptables --version Identify nft vs legacy
Switch mode update-alternatives --set ... legacy Use legacy backend
Restart Docker sudo service docker restart Reload NAT rules
Verify sudo iptables -t nat -L Confirm DOCKER chain exists

🚀 Conclusion

This “Failed to Setup IP tables” issue is one of the most frequent Docker-on-WSL2 networking errors.
The root cause lies in the nftables vs legacy backend mismatch — a subtle but critical difference in Linux networking subsystems.
Once you switch to the legacy backend and restart Docker, everything should work smoothly again.

By keeping your WSL2 kernel, Docker Engine, and iptables configuration aligned, you can prevent these issues and maintain a stable developer environment on Windows.

Happy containerizing! 🐋

PostHeaderIcon How to Install an Old Version of Docker on a Recent Debian: A Case Study with Docker 20.10.9 on Debian 13 (Trixie)

In the rapidly evolving landscape of containerization technology, Docker remains a cornerstone for developers and system administrators. However, specific use cases—such as legacy application compatibility, testing, or reproducing historical environments—may necessitate installing an older version of Docker on a modern operating system. This guide provides a detailed walkthrough for installing Docker Engine 20.10.9, a release from September 2021, on Debian 13 (codename “Trixie”), the testing branch of Debian as of September 2025. While the steps can be adapted for other versions or Debian releases, this case study addresses the unique challenges of downgrading Docker on a contemporary distribution.

Introduction: The Challenges and Rationale for Installing an Older Docker Version

Installing an outdated Docker version like 20.10.9 on a recent Debian release such as Trixie is fraught with challenges due to Docker’s evolution and Debian’s forward-looking package management. Docker transitioned from Calendar Versioning (CalVer, e.g., 20.10) to Semantic Versioning (SemVer, starting with 23.0 in May 2023), introducing significant updates in security, features, and dependencies. This creates several obstacles:

  • Package Availability and Compatibility: Docker’s official APT repository prioritizes current versions (e.g., 28.x in 2025) for supported Debian releases. Older versions like 20.10.9 are often archived and unavailable via apt for newer codenames like Trixie, requiring manual downloads of .deb packages from a compatible release (e.g., bullseye for Debian 11). This can lead to dependency mismatches or installation failures.
  • Security and Support Risks: Version 20.10.9 is end-of-life (EOL) since mid-2023, lacking official security patches for known vulnerabilities (e.g., CVEs in networking or containerd). This poses risks for production environments. Additionally, compatibility issues may arise with modern WSL2 networking in Windows Subsystem for Linux (WSL) environments.
  • Dependency Conflicts: Older Docker versions rely on specific versions of components like containerd.io, which may conflict with newer libraries on Debian 13, potentially causing installation or runtime errors.
  • Docker Compose Compatibility: Modern Docker integrates Compose as a plugin (docker compose), but older setups require the standalone docker-compose (v1, with hyphen), necessitating a separate binary installation.

Why pursue this downgrade? Legacy applications, specific toolchains, or compatibility with older Dockerfiles may require it—such as maintaining a telemetry stack with Elasticsearch, Kibana, and APM Server in a controlled environment. However, for production or security-sensitive deployments, upgrading to the latest Docker version (e.g., 28.3.3) is strongly recommended. This guide assumes a WSL/Debian Trixie setup but is applicable to native Debian installations, with precautions for data loss and system stability.

Prerequisites

Before proceeding, ensure the following:

  • A running Debian 13 (Trixie) system (verify with lsb_release -cs).
  • Administrative access (sudo privileges).
  • Backup of critical Docker data (e.g., export volumes using docker volume ls).
  • Internet access for downloading packages.
  • Awareness of risks: Manual package installation bypasses APT’s dependency resolution, and EOL versions lack security updates.

Step 1: Prune All Local Docker Resources

Why This Step is Needed

Before uninstalling the current Docker version (e.g., 28.3.3), pruning all local resources—images, containers, volumes, and networks—ensures a clean slate. This prevents conflicts from residual data, reclaims disk space, and prepares the system for the downgrade. Since pruning is irreversible, backing up critical data (e.g., telemetry stack volumes) is essential.

What It Does

The docker system prune command removes all unused Docker artifacts, including stopped containers, unused images, volumes, and networks, ensuring no remnants interfere with the new installation.

Commands


# Stop all running containers (if any)
docker stop $(docker ps -q) 2>/dev/null || true

# Prune everything: images, containers, volumes, networks, and build cache
docker system prune -a --volumes -f
    

Verification

Run these commands to confirm cleanup:


docker images -a  # Should list no images
docker volume ls  # Should be empty
docker network ls # Should show only defaults (bridge, host, none)
docker ps -a      # Should show no containers
    

If permission errors occur, verify your user is in the docker group (sudo usermod -aG docker $USER and log out/in) or use sudo.

Step 2: Remove the Current Docker Installation

Why This Step is Needed

Removing the existing Docker version (e.g., 28.3.3) eliminates potential conflicts in packages, configurations, or runtime components. Residual files or newer dependencies could cause the older 20.10.9 installation to fail or behave unpredictably.

What It Does

This step stops Docker services, purges installed packages, deletes data directories and configurations, and removes the Docker APT repository to prevent accidental upgrades to newer versions.

Commands


# Stop Docker services
sudo systemctl stop docker
sudo systemctl stop docker.socket

# Uninstall Docker packages
sudo apt-get purge -y docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin docker-ce-rootless-extras
sudo apt-get autoremove -y --purge

# Remove Docker data and configs
sudo rm -rf /var/lib/docker
sudo rm -rf /var/lib/containerd
sudo rm -rf /etc/docker
sudo rm -f /etc/apparmor.d/docker
sudo rm -f /var/run/docker.sock
sudo groupdel docker 2>/dev/null || true

# Remove Docker repository
sudo rm -f /etc/apt/sources.list.d/docker.list
sudo rm -f /etc/apt/keyrings/docker.gpg
sudo apt-get update

# Verify removal
docker --version  # Should show "command not found"
    

Reboot WSL if needed (in Windows PowerShell: wsl --shutdown).

Step 3: Install Docker Engine 20.10.9 via Manual .deb Packages

Why This Step is Needed

Debian Trixie’s Docker repository does not include 20.10.9, as it is an EOL version from 2021, unsupported since mid-2023. The standard apt installation fails due to version mismatches, so we manually download and install .deb packages from Docker’s archive for Debian 11 (bullseye), which is compatible with Trixie. This approach bypasses repository limitations but requires careful dependency management.

What It Does

The commands download specific .deb files for Docker CE, CLI, and containerd.io, install them using dpkg, resolve dependencies with apt, and lock the version to prevent upgrades. The process also ensures Docker starts correctly and is accessible without root privileges.

Commands


# Install prerequisites
sudo apt-get update
sudo apt-get install -y ca-certificates curl gnupg lsb-release

# Create directory for downloads
mkdir -p ~/docker-install
cd ~/docker-install

# Download .deb packages for 20.10.9 (bullseye, amd64)
curl -O https://download.docker.com/linux/debian/dists/bullseye/pool/stable/amd64/containerd.io_1.4.13-1_amd64.deb
curl -O https://download.docker.com/linux/debian/dists/bullseye/pool/stable/amd64/docker-ce-cli_20.10.9~3-0~debian-bullseye_amd64.deb
curl -O https://download.docker.com/linux/debian/dists/bullseye/pool/stable/amd64/docker-ce_20.10.9~3-0~debian-bullseye_amd64.deb

# Verify file sizes (should be MBs, not bytes)
ls -lh *.deb

# Install .deb packages
sudo dpkg -i containerd.io_1.4.13-1_amd64.deb
sudo dpkg -i docker-ce-cli_20.10.9~3-0~debian-bullseye_amd64.deb
sudo dpkg -i docker-ce_20.10.9~3-0~debian-bullseye_amd64.deb

# Fix any dependency issues
sudo apt-get install -f

# Hold versions to prevent upgrades
sudo apt-mark hold docker-ce docker-ce-cli containerd.io

# Start and enable Docker
sudo systemctl start docker
sudo systemctl enable docker

# Add user to docker group (log out/in after)
sudo usermod -aG docker $USER

# Verify installation
docker --version  # Should show "Docker version 20.10.9, build ..."
docker run --rm hello-world  # Test pull and run

# Clean up downloaded files
cd /mnt/c/workarea/development-tools/telemetry-poc/etc/docker/telemetry
rm -rf ~/docker-install
    

Note: If the curl URLs return 404 errors, browse Docker’s bullseye pool to find the exact filenames (e.g., try docker-ce_20.10.10~3-0~debian-bullseye_amd64.deb if 20.10.9 is unavailable). Use containerd.io_1.4.11-1_amd64.deb if 1.4.13 fails.

Step 4: Install Standalone docker-compose (v1.29.2)

Why This Step is Needed

Modern Docker includes Compose as a plugin (docker compose, v2), but legacy setups like 20.10.9 often require the standalone docker-compose (v1, with hyphen) for compatibility with older workflows or scripts. This binary ensures the hyphenated command is available.

What It Does

Downloads the v1.29.2 binary (the last v1 release, compatible with 20.10.9) from GitHub, installs it to /usr/local/bin, and makes it executable.

Commands


sudo curl -L "https://github.com/docker/compose/releases/download/1.29.2/docker-compose-$(uname -s)-$(uname -m)" -o /usr/local/bin/docker-compose
sudo chmod +x /usr/local/bin/docker-compose

# Verify
docker-compose --version  # Should show "docker-compose version 1.29.2, build ..."
    

Step 5: Post-Installation and Verification

Why This Step is Needed

Post-installation steps ensure Docker and docker-compose function correctly, especially in a WSL environment where networking can be temperamental. Verifying the setup confirms compatibility with your telemetry stack (e.g., Elasticsearch, Kibana, APM Server).

What It Does

Restarts WSL to apply changes, tests Docker and docker-compose, and rebuilds your telemetry stack. It also checks network accessibility from Windows.

Commands


# Restart WSL (in Windows PowerShell)
wsl --shutdown

# Reopen WSL terminal and verify
docker --version  # Should show "Docker version 20.10.9, build ..."
docker-compose --version  # Should show "docker-compose version 1.29.2, build ..."
docker run --rm hello-world

Troubleshooting

If issues arise, consider these steps:

  • Download Failures: Check Docker’s bullseye pool for correct filenames. Use curl -I <URL> to verify HTTP status (200 OK).
  • Dependency Errors: Run sudo apt-get install -f to resolve.
  • Docker Not Starting: Check sudo systemctl status docker or journalctl -u docker.
  • WSL Networking: Update WSL (wsl --update) and restart Docker (sudo service docker restart).
  • Share Outputs: Provide ls -lh ~/docker-install/*.deb, dpkg -l | grep docker, or error messages for debugging.

Conclusion

Installing an older version of Docker, such as 20.10.9, on a recent Debian release like Trixie (Debian 13) is a complex but achievable task, requiring careful management of package dependencies and manual installation of archived .deb files. By pruning existing Docker resources, removing the current installation, and installing bullseye-compatible packages, you can successfully downgrade to meet legacy requirements. The addition of the standalone docker-compose ensures compatibility with older workflows..

However, this approach comes with caveats: version 20.10.9 is end-of-life, lacking security updates, and may face compatibility issues with modern tools or WSL2 networking. For production environments, consider using the latest Docker version (e.g., 28.3.3 as of September 2025) to benefit from ongoing support and enhanced features. Always test thoroughly after installation, and maintain backups to mitigate data loss risks. If you encounter issues or need to adapt this process for other versions, consult Docker’s official repository or community forums for additional resources.

PostHeaderIcon Script to clean WSL and remove Ubuntu from Windows 11

Here is a fully automated PowerShell script that will:

  1. Unregister and remove all WSL distros

  2. Reset WSL to factory defaults

  3. Optionally reinstall WSL cleanly (commented out)

⚠️ You must run this script as Administrator

# =====================================================
# WSL Full Reset Script for Windows 11
# Removes all distros and resets WSL system features
# MUST BE RUN AS ADMINISTRATOR
# =====================================================

Write-Host "`n== STEP 1: List and remove all WSL distros ==" -ForegroundColor Cyan

$distros = wsl --list --quiet
foreach ($distro in $distros) {
    Write-Host "Unregistering WSL distro: $distro" -ForegroundColor Yellow
    wsl --unregister "$distro"
}

Start-Sleep -Seconds 2

Write-Host "`n== STEP 2: Disable WSL-related Windows features ==" -ForegroundColor Cyan

dism.exe /online /disable-feature /featurename:VirtualMachinePlatform /norestart
dism.exe /online /disable-feature /featurename:Microsoft-Windows-Subsystem-Linux /norestart

Start-Sleep -Seconds 2

Write-Host "`n== STEP 3: Uninstall WSL kernel update (if present) ==" -ForegroundColor Cyan
$wslUpdate = Get-AppxPackage -AllUsers | Where-Object { $_.Name -like "*Microsoft.WSL2*" }
if ($wslUpdate) {
    winget uninstall --id "Microsoft.WSL2" --silent
} else {
    Write-Host "No standalone WSL kernel update found." -ForegroundColor DarkGray
}

Start-Sleep -Seconds 2

Write-Host "`n== STEP 4: Clean leftover configuration files ==" -ForegroundColor Cyan
$paths = @(
    "$env:USERPROFILE\.wslconfig",
    "$env:APPDATA\Microsoft\Windows\WSL",
    "$env:LOCALAPPDATA\Packages\CanonicalGroupLimited*",
    "$env:LOCALAPPDATA\Docker",
    "$env:USERPROFILE\.docker"
)
foreach ($path in $paths) {
    Write-Host "Removing: $path" -ForegroundColor DarkYellow
    Remove-Item -Recurse -Force -ErrorAction SilentlyContinue $path
}

Write-Host "`n== STEP 5: Reboot Required ==" -ForegroundColor Magenta
Write-Host "Please restart your computer to complete the WSL reset process."

# Optional: Reinstall WSL cleanly (after reboot)
# Uncomment the lines below if you want the script to also reinstall WSL
<# 
Write-Host "`n== STEP 6: Reinstall WSL ==" -ForegroundColor Cyan
wsl --install
#>

PostHeaderIcon Running Docker Natively on WSL2 (Ubuntu 24.04) in Windows 11

For many developers, Docker Desktop has long been the default solution to run Docker on Windows. However, licensing changes and the desire for a leaner setup have pushed teams to look for alternatives. Fortunately, with the maturity of Windows Subsystem for Linux 2 (WSL2), it is now possible to run the full Docker Engine directly inside a Linux distribution such as Ubuntu 24.04, while still accessing containers seamlessly from both Linux and Windows.

In this guide, I’ll walk you through a clean, step-by-step setup for running Docker Engine inside WSL2 without Docker Desktop, explain how Windows and WSL2 communicate, and share best practices for maintaining a healthy development environment.


Why Run Docker Inside WSL2?

Running Docker natively inside WSL2 has several benefits:

  • No licensing issues – you avoid Docker Desktop’s commercial license requirements.
  • Lightweight – no heavy virtualization layer; containers run directly inside your WSL Linux distro.
  • Integrated networking – on Windows 11 with modern WSL versions,
    containers bound to localhost inside WSL are automatically reachable from Windows.
  • Familiar Linux workflow – you install and use Docker exactly as you would on a regular Ubuntu server.

Step 1 – Update Ubuntu

Open your Ubuntu 24.04 terminal and ensure your system is up to date:

sudo apt update && sudo apt upgrade -y

Step 2 – Install Docker Engine

Install Docker using the official Docker repository:

# Install prerequisites
sudo apt install -y ca-certificates curl gnupg lsb-release

# Add Docker’s GPG key
sudo install -m 0755 -d /etc/apt/keyrings
curl -fsSL https://download.docker.com/linux/ubuntu/gpg | \
  sudo gpg --dearmor -o /etc/apt/keyrings/docker.gpg

# Configure Docker repository
echo \
  "deb [arch=$(dpkg --print-architecture) signed-by=/etc/apt/keyrings/docker.gpg] \
  https://download.docker.com/linux/ubuntu $(lsb_release -cs) stable" | \
  sudo tee /etc/apt/sources.list.d/docker.list > /dev/null

# Install Docker Engine
sudo apt update
sudo apt install -y docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin

Step 3 – Run Docker Without sudo

To avoid prefixing every command with sudo, add your user to the docker group:

sudo usermod -aG docker $USER

Restart your WSL terminal for the change to take effect, then verify:

docker --version
docker ps

Step 4 – Test Networking

One of the most common questions is:
“Will my containers be accessible from both Ubuntu and Windows?”
The answer is yes on modern Windows 11 with WSL2.
Let’s test it by running an Nginx container:

docker run -d -p 8080:80 --name webtest nginx
  • Inside Ubuntu (WSL): curl http://localhost:8080
  • From Windows (browser or PowerShell): http://localhost:8080

Thanks to WSL2’s localhost forwarding, Windows traffic to localhost is routed
into the WSL network, making containers instantly accessible without extra configuration.


Step 5 – Run Multi-Container Applications with Docker Compose

The Docker Compose plugin is already installed as part of the package above. Check the version:

docker compose version

Create a docker-compose.yml for a WordPress + MySQL stack:

version: "3.9"
services:
  db:
    image: mysql:8.0
    environment:
      MYSQL_ROOT_PASSWORD: rootpass
      MYSQL_DATABASE: wordpress
      MYSQL_USER: wpuser
      MYSQL_PASSWORD: wppass
    volumes:
      - db_data:/var/lib/mysql

  wordpress:
    image: wordpress:latest
    ports:
      - "8080:80"
    environment:
      WORDPRESS_DB_HOST: db:3306
      WORDPRESS_DB_USER: wpuser
      WORDPRESS_DB_PASSWORD: wppass
      WORDPRESS_DB_NAME: wordpress

volumes:
  db_data:

Start the services:

docker compose up -d

Once the containers are running, open http://localhost:8080 in your Windows browser
to access WordPress. The containers are managed entirely inside WSL2,
but networking feels seamless.


Maintenance: Cleaning Up Docker Data

Over time, Docker accumulates images, stopped containers, volumes, and networks.
This can take up significant disk space inside your WSL distribution.
Here are safe maintenance commands to keep your environment clean:

Remove Unused Objects

docker system prune -a --volumes
  • -a: removes all unused images, not just dangling ones
  • --volumes: also removes unused volumes

Reset Everything (Dangerous)

If you need to wipe your Docker environment completely (images, containers, volumes, networks):

docker stop $(docker ps -aq) 2>/dev/null
docker rm -f $(docker ps -aq) 2>/dev/null
docker volume rm $(docker volume ls -q) 2>/dev/null
docker network rm $(docker network ls -q) 2>/dev/null
docker image rm -f $(docker image ls -q) 2>/dev/null

⚠️ Use this only if you want to start fresh. All data will be removed.


Conclusion

By running Docker Engine directly inside WSL2, you gain a powerful, lightweight, and license-free Docker environment that integrates seamlessly with Windows 11. Your containers are accessible from both Linux and Windows, Docker Compose works out of the box, and maintenance is straightforward with prune commands.

This approach is particularly well-suited for developers who want the flexibility of Docker without the overhead of Docker Desktop. With WSL2 and Ubuntu 24.04, you get the best of both worlds: Linux-native Docker with Windows accessibility.