# Wsl Configuration

> WSL Configuration

- Skill: `lucadominguez/wsl-configuration` (Agent Skill)
- Install (CLI): `npx skillmds@latest add lucadominguez/wsl-configuration`
- Raw SKILL.md: https://api.skillmd.com/api/skills/lucadominguez/wsl-configuration/raw
- Safety review: pending
- Works with: Claude Code, Claude.ai, OpenAI Codex
- Category: Coding & Dev Tools
- Author: lucadominguez (https://skillmd.com/u/lucadominguez)
- Updated: 2026-09-17
- Page: https://skillmd.com/skills/lucadominguez/wsl-configuration

---

# WSL Configuration

WSL (Windows Subsystem for Linux) configuration tasks: SSH access, networking modes, firewall rules, and calling Windows tools from the Linux side.

## Trigger conditions

Load this skill when the user:
- Wants SSH access into their WSL from another device
- Asks about WSL networking (IP, port forwarding, mirrored mode)
- Runs PowerShell commands from WSL and they fail mysteriously
- Needs to expose a WSL service to the LAN
- Needs Docker in WSL but `docker` command is missing (Docker Desktop is installed on Windows side)

## Docker Desktop integration (WSL)

Docker Desktop installed on Windows but not reachable from WSL. The `docker` CLI is missing in WSL's PATH even though `docker.exe` works from PowerShell.

### Detection

```bash
# Docker CLI missing in WSL
which docker          # → not found

# But docker.exe IS reachable via WSL interop
which docker.exe      # → /mnt/c/Program Files/Docker/Docker/resources/bin/docker.exe
docker.exe --version  # → Docker version 28.x.x
```

### Fix

```bash
# 1. Symlink docker.exe → docker in WSL PATH
ln -sf "/mnt/c/Program Files/Docker/Docker/resources/bin/docker.exe" ~/.local/bin/docker

# 2. Verify
which docker && docker --version
```

### Starting Docker Desktop from WSL

If Docker Desktop isn't running:

```bash
# Start it
"/mnt/c/Program Files/Docker/Docker/Docker Desktop.exe" &

# Wait for the daemon to be ready (up to 30s)
for i in $(seq 1 30); do
  docker ps >/dev/null 2>&1 && echo "Docker is ready!" && break
  sleep 1
done
```

### Pitfalls

- **`shutil.which("docker")` won't find `docker.exe`.** Python's `shutil.which()` and shell `which docker` look for an executable named exactly `docker` — they don't try `.exe` extensions. The symlink is required for tools that probe for `docker` by name (Strix, Docker SDKs, CI scripts).

- **Some CLIs hang without Docker.** Strix's `main()` calls `check_docker_installed()` before argument parsing, so even `--help` hangs if Docker isn't available. Always resolve Docker availability first.

- **Docker Desktop must be running for the daemon.** The `docker` CLI is useless without the daemon. Starting Docker Desktop via the `.exe` from WSL works — the GUI window will appear on the Windows desktop and the daemon becomes available in ~10-20 seconds.

## SSH access into WSL (from phone, other machines)

Goal: SSH into WSL as if it were a normal Linux box on the LAN.

### 1. Install & configure SSH server

```bash
sudo apt install openssh-server -y
sudo systemctl enable ssh --now
```

Verify: `sudo systemctl status ssh` — should show "Server listening on 0.0.0.0 port 22."

Default config allows password auth out of the box on Ubuntu. Confirm the user has a password set: `sudo passwd -S <user>` — status "P" means password is set.

### 2. Enable mirrored networking

WSL2 by default uses NAT (internal IP like 172.x.x.x) — unreachable from LAN. Mirrored mode makes WSL share the Windows host IP.

Write to `C:\Users\<user>\.wslconfig`:
```ini
[wsl2]
networkingMode=mirrored
```

This requires a WSL restart to take effect: from PowerShell/CMD, run `wsl --shutdown`, then reopen WSL.

### 3. Open Windows Firewall

Windows Firewall blocks incoming SSH by default. From an **admin** PowerShell:
```powershell
New-NetFirewallRule -DisplayName "WSL SSH" -Direction Inbound -Protocol TCP -LocalPort 22 -Action Allow -Profile Private
```

### 4. Get the Windows LAN IP

```bash
ipconfig.exe | grep -B1 -A3 'Wi-Fi'
```

Look for the Wi-Fi adapter's IPv4 (e.g., `192.168.1.78`).

### 5. Connect

From phone/remote: `ssh <user>@<windows-lan-ip>` with the WSL user's password.

## Pitfall: PowerShell `$_` gets eaten by bash

When calling `powershell.exe` from WSL bash, the PowerShell pipeline variable `$_` gets expanded by bash as a shell variable (to empty string), silently breaking `Where-Object` and `ForEach-Object` blocks.

**Symptom:** PowerShell errors like `'/mnt/c/Users/Lenovo.PropertyName' is not recognized` — bash expanded `$_.PropertyName` to `/mnt/c/Users/Lenovo.PropertyName`.

**Fix:** Use `ipconfig.exe` directly instead of PowerShell for network info:
```bash
# Works — no $ escaping
ipconfig.exe | grep 'Wi-Fi'

# Avoid — $_ gets bash-expanded silently
powershell.exe -Command "Get-NetIPAddress | Where-Object { $_.InterfaceAlias -match 'Wi-Fi' }"
```

For non-avoidable PowerShell, escape the `$`:
```bash
powershell.exe -Command "Get-NetIPAddress | Where-Object { \$_.InterfaceAlias -match 'Wi-Fi' }"
```

## Pitfall: Firewall rules need admin

`New-NetFirewallRule` and `netsh advfirewall` both require elevated PowerShell. Non-admin calls fail with "Access is denied." The user must run these manually.
