Let’s say you have a Windows machine and want to be able to SSH into the WSL2 subsystem from your network.

First we need to make sure that the sshd in the WSL2 guest system is always running:

Install sshd (duh)

apt update
apt install openssh-server

Oh, lets config things in /etc/ssh/sshd_config:

PermitRootLogin yes # root user
PasswordAuthentication no # use keys

Run sshd in Windows 11

Windows 11 has implemented systemd support: https://learn.microsoft.com/en-us/windows/wsl/systemd

In the WSL2 guest:

echo -e "[boot]\nsystemd=true" > /etc/wsl.conf

Restart WSL:

`wsl.exe --shutdown`

Again, in the guest system:

sudo systemctl enable --now ssh

Run sshd in Windows 10

The systemd method doesn’t work. So, what to do? There are a few approaches but here’s the one I used.

In the WSL guest (eg Ubuntu) create a simple script /root/run.sh:

#!/bin/bash

while [ 1 ];
do
	sleep 1;
done

The goal of this script is just to run forever.

Then, create a PowerShell script say at C:\run-wsl-hidden.ps1 - a PowerShell script is required to run it “hidden”:

Start-Process wsl.exe -ArgumentList "-d Ubuntu /root/run.sh" -WindowStyle Hidden

Once you’ve created this, you should open the Task Scheduler app and:

  • Create Basic Task
  • Trigger:
    • at startup
  • Action:
    • Start a program
  • Program:
    • powershell.exe
  • Arguments
    • -WindowStyle Hidden -ExecutionPolicy Bypass -File "C:\run-wsl-hidden.ps1"

Make it accessible externally

We want to make sure we are port forwarding from Windows to the WSL

# In PowerShell as Administrator
netsh interface portproxy add v4tov4 listenport=22 listenaddress=0.0.0.0 connectport=22 connectaddress=(wsl hostname -I)
  • You can get your WSL IP: ip addr show eth0 | grep "inet\b" | awk '{print $2}' | cut -d/ -f1 but using the hostname is more reliable

We need to allow connecting via SSH:

# Run in PowerShell as Administrator
New-NetFirewallRule -DisplayName "WSL2 SSH" -Direction Inbound -Action Allow -Protocol TCP -LocalPort 22
  • You might have a port conflict if the Windows SSH server is also running, just shut that down

In PowerShell, you might wan to check on DNS (in theory mDNS should work):

# Run in PowerShell as Administrator
Get-Service "DNSCache" | Set-Service -StartupType Automatic
Start-Service "DNSCache"

IPv6 Debugging

If you have long hang times connecting, it could be IPv6 routing woes. Try w/ IPv4:

ssh -4 windows.local

If that fixes things you can put this in your ~/.ssh/config:

Host windows.local
    AddressFamily inet
    User root # you probably want this here anyway
  • You could also try putting AddressFamily inet in your WSL guest’s /etc/ssh/sshd_config