WSL icon indicating copy to clipboard operation
WSL copied to clipboard

WSL2 Ubuntu 24.04: Restrictive Ephemeral Port Range Breaks Docker Container Orchestration

Open garysassano opened this issue 1 month ago • 7 comments

Windows Version

10.0.26100.6899

WSL Version

2.6.1.0

Are you using WSL 1 or WSL 2?

  • [x] WSL 2
  • [ ] WSL 1

Kernel Version

6.6.87.2-1

Distro Version

Ubuntu 24.04

Other Software

No response

Repro Steps

  1. Install Docker Desktop with WSL2 backend on Windows

  2. Install/use Ubuntu 24.04 LTS distribution in WSL2

  3. Open Ubuntu WSL2 terminal and check the ephemeral port range:

    cat /proc/sys/net/ipv4/ip_local_port_range
    

    Observe: Output shows 44620 48715 (only 4,096 ports) Expected: Should show 32768 60999 (standard Linux default: 28,232 ports)

  4. Attempt to spawn multiple Docker containers with dynamic port allocation:

    # Try spawning containers with random host ports
    for i in {1..10}; do
      docker run -d --rm -p 0.0.0.0:0:80 nginx
    done
    
  5. Observe errors like:

    docker: Error response from daemon: ports are not available: 
    exposing port TCP 0.0.0.0:48185 -> 127.0.0.1:0: listen tcp 0.0.0.0:48185: 
    bind: Only one usage of each socket address (protocol/network address/port) 
    is normally permitted.
    
  6. Note that all failed port numbers fall within the restricted range (44620-48715)

  7. Verify minimal system load:

    # Check active connections in ephemeral range
    ss -tan | awk '{print $4}' | grep -oE ':[0-9]+$' | grep -oE '[0-9]+' |      awk '$1 >= 44620 && $1 <= 48715' | wc -l
    # Output: ~8 connections (minimal load)
    
    # Check running containers
    docker ps | wc -l
    # Output: 1-2 containers (minimal load)
    

Result: Docker fails to allocate ports despite minimal system activity, proving the range is too restrictive.

Expected Behavior

WSL2 should use the standard Linux ephemeral port range (32768-60999) to:

  1. Match behavior of native Linux distributions
  2. Provide sufficient ports for concurrent Docker containers
  3. Avoid conflicts with Docker's dynamic port allocation mechanism (49153-65535)
  4. Support enterprise CI/CD workflows and automated testing frameworks
  5. Allow 10+ concurrent containers with dynamic port binding

Reference: Standard Linux systems (Ubuntu Server, RHEL, Debian) all default to 32768-60999 for ephemeral ports. This is documented in kernel.org and is the expected behavior for any Linux environment.

Docker Desktop expectation: When running Docker Desktop with WSL2 backend, users expect Docker's dynamic port allocation (docker run -p 0:80) to work reliably for concurrent containers, as it does on native Linux.

Actual Behavior

WSL2 Ubuntu 24.04 uses an abnormally restrictive ephemeral port range (44620-48715) that causes:

Port Exhaustion Under Normal Load:

  • Only 4,096 available ephemeral ports (7x smaller than standard Linux)
  • Docker's dynamic port allocation consistently fails
  • Automated container orchestration becomes impossible

Real-world failure example:

Building task-specific Docker image for fix-broken-deployment...
Specimen Docker image built successfully!
100%|██████████| 1/1 [00:28<00:00, 29.00s/it]

⚠ Container startup failed (attempt 1/3): Failed to start container: 
docker: Error response from daemon: ports are not available: 
exposing port TCP 0.0.0.0:48185 -> 127.0.0.1:0: listen tcp 0.0.0.0:48185: 
bind: Only one usage of each socket address (protocol/network address/port) 
is normally permitted.

  Retrying with new container and port...

⚠ Container startup failed (attempt 2/3): Failed to start container: 
docker: Error response from daemon: ports are not available: 
exposing port TCP 0.0.0.0:47941 -> 127.0.0.1:0: listen tcp 0.0.0.0:47941: 
bind: Only one usage of each socket address is normally permitted.

  Retrying with new container and port...

✗ Container startup failed after 3 attempts: Failed to start container: 
docker: Error response from daemon: ports are not available: 
exposing port TCP 0.0.0.0:46025 -> 127.0.0.1:0: listen tcp 0.0.0.0:46025: 
bind: Only one usage of each socket address is normally permitted.

Task failed with exception: Failed to start container [...]

Pattern observed: All attempted ports (48185, 47941, 46025, 45239, 45511, 45075, 46217, 44641, 46353, 46907, 45377) fall within the 44620-48715 range and fail consistently.

Impact on workflows:

  • ✗ Automated testing frameworks fail (e.g., apex-arena with 10 concurrent evaluation runs)
  • ✗ CI/CD pipelines cannot spawn parallel containers
  • ✗ Docker Compose with multiple services experiences random failures
  • ✗ Development workflows with microservices break intermittently
  • ✗ Kubernetes testing in WSL2 becomes unreliable

System state at failure:

$ cat /proc/sys/net/ipv4/ip_local_port_range
44620   48715

$ ss -tan | awk '{print $4}' | grep -oE ':[0-9]+$' | grep -oE '[0-9]+' |   awk '$1 >= 44620 && $1 <= 48715' | wc -l
8  # Only 8 active connections

$ docker ps | wc -l
1  # Only 1 running container

# Yet Docker cannot allocate ports - the range is simply too small

Workaround that confirms root cause:

# Expanding to standard Linux range immediately resolves the issue
echo "net.ipv4.ip_local_port_range = 32768 60999" | sudo tee -a /etc/sysctl.conf
sudo sysctl -p

# After fix: Docker containers spawn successfully
$ for i in {1..10}; do docker run -d --rm -p 0:80 nginx; done
# All 10 containers start successfully ✓

This proves the issue is WSL2's non-standard ephemeral port configuration, not Docker or user error.

Diagnostic Logs

Ephemeral Port Range (Before Fix):

$ cat /proc/sys/net/ipv4/ip_local_port_range
44620   48715

Active Connections in Ephemeral Range:

$ ss -tan | awk '{print $4}' | grep -oE ':[0-9]+$' | grep -oE '[0-9]+' |   sort -n | awk '$1 >= 44620 && $1 <= 48715'
45487
45487
45487
45669
46824
47114
47120
47392

# Total active: 8 connections

Docker Containers:

$ docker ps -a --format "table {{.ID}}	{{.Image}}	{{.Status}}	{{.Ports}}"
CONTAINER ID   IMAGE           STATUS          PORTS
3f7beeaec544   nebula-devops   Up 59 minutes   0.0.0.0:80->80/tcp, [...], 0.0.0.0:6443->6443/tcp

# Only 1 container running, minimal port usage

TIME-WAIT Connections:

$ ss -tan state time-wait | wc -l
1  # Minimal TIME-WAIT state

Attempted Port Allocations (from error logs): All these ports failed to bind:

  • 48185, 47941, 46025 (first task, 3 attempts)
  • 45239, 45511, 45075 (second task, 3 attempts)
  • 46217, 44641, 46353 (third task, 3 attempts)
  • 46907, 45377, ... (fourth task, attempts)

All ports fall within the restricted range 44620-48715.

Successful Fix Verification:

# After applying workaround
$ cat /proc/sys/net/ipv4/ip_local_port_range
32768   60999  # Standard Linux range

# Docker now works reliably
$ docker run -d --rm -p 0:80 nginx
<container_id>  # Success ✓

Related Issue: This appears related to #12228 which documents the same restrictive port range causing conflicts with Windows applications. The issue affects Docker Desktop users specifically when using dynamic port allocation.

Request: Please update WSL2's default ephemeral port range to match standard Linux distributions (32768-60999) to ensure compatibility with Docker Desktop and modern containerized development workflows.

garysassano avatar Nov 08 '25 23:11 garysassano

Logs are required for review from WSL team

If this a feature request, please reply with '/feature'. If this is a question, reply with '/question'. Otherwise, please attach logs by following the instructions below, your issue will not be reviewed unless they are added. These logs will help us understand what is going on in your machine.

How to collect WSL logs

Download and execute collect-wsl-logs.ps1 in an administrative powershell prompt:

Invoke-WebRequest -UseBasicParsing "https://raw.githubusercontent.com/microsoft/WSL/master/diagnostics/collect-wsl-logs.ps1" -OutFile collect-wsl-logs.ps1
Set-ExecutionPolicy Bypass -Scope Process -Force
.\collect-wsl-logs.ps1

The script will output the path of the log file once done.

If this is a networking issue, please use collect-networking-logs.ps1, following the instructions in Collect WSL logs for networking issues

Once completed please upload the output files to this GitHub issue.

See Collect WSL logs (recommended method).

If you choose to email these logs instead of attaching them to the bug, please send them to [email protected] with the GitHub issue number in the subject, and include a link to your GitHub issue comment in the message body, and reply with '/emailed-logs'.

github-actions[bot] avatar Nov 08 '25 23:11 github-actions[bot]

Diagnostic information
.wslconfig found
Detected appx version: 2.6.1.0

github-actions[bot] avatar Nov 08 '25 23:11 github-actions[bot]

@CatalinFetoiu: Looks like WSL's mirrored networking port range is conflicting with docker. Maybe we should increase the range here ?

OneBlue avatar Nov 11 '25 22:11 OneBlue

@OneBlue @garysassano thanks for reporting the issue it's unexpected that binding to those ports fails - e.g. from your output it looks like there is no one listening on 48185, yet binding to this fails

could you please collect networking logs, using https://github.com/microsoft/WSL/blob/master/diagnostics/collect-networking-logs.ps1?

thanks

CatalinFetoiu avatar Nov 12 '25 22:11 CatalinFetoiu

@CatalinFetoiu I wasn't able to track down the project that originally caused the issue on port 48185, but I've now run into the same problem on port 8001 instead.

WslNetworkingLogs-2025-11-15_00-28-09.zip

garysassano avatar Nov 15 '25 00:11 garysassano

Diagnostic information
.wslconfig found
Detected appx version: 2.6.1.0
optional-components.txt not found

github-actions[bot] avatar Nov 15 '25 00:11 github-actions[bot]