Skip to main content

SSH and Remote Access in WSL

If you just want to open a WSL terminal locally on Windows, you don't actually need SSH. But SSH becomes very useful when you want to do the following:

  • Connect to WSL uniformly from Windows Terminal, VS Code, or other terminal tools
  • Log in to your WSL environment from another machine on the LAN
  • Run development services long-term in WSL, with SSH forwarding or remote development

This document splits the entire pipeline into two layers:

  1. First get the SSH service inside WSL working properly
  2. Then decide whether to allow only Windows local access or access from other LAN machines

1. Installing OpenSSH in WSL

The following examples use Ubuntu / Debian:

sudo apt update
sudo apt install -y openssh-server

After installation, first confirm the service file exists:

sshd -T | head

If the system says sshd is not found, it usually means openssh-server has not been installed successfully.

2. Configure the Minimum SSH Security Baseline

Edit the configuration file:

sudo nano /etc/ssh/sshd_config

It is recommended to at least confirm these settings:

Port 22
ListenAddress 0.0.0.0
PubkeyAuthentication yes
PasswordAuthentication no
PermitRootLogin no
AuthorizedKeysFile .ssh/authorized_keys

The default approach here is:

  • Prefer public key authentication
  • Don't allow root login by default
  • Don't keep password login by default

If you are just testing temporarily, you can also change PasswordAuthentication to yes, and turn it back off after confirming public key login works.

3. Generate and Import the Public Key

If you don't have an SSH key yet, generate one on the client machine first. Using Windows PowerShell as an example:

ssh-keygen -t ed25519 -C "your_email@example.com"

After generation, view the public key content:

Get-Content $env:USERPROFILE\.ssh\id_ed25519.pub

Then append the public key to the WSL user's authorized_keys:

mkdir -p ~/.ssh
chmod 700 ~/.ssh
nano ~/.ssh/authorized_keys
chmod 600 ~/.ssh/authorized_keys

If permissions are wrong, SSH will often simply ignore this file, so don't skip this step.

4. Start the SSH Service

First determine whether your WSL has systemd enabled.

Method A: systemd Enabled

If you have already enabled systemd in your /etc/wsl.conf:

[boot]
systemd=true

Then you can directly use:

sudo systemctl enable --now ssh
sudo systemctl status ssh

After modifying wsl.conf, remember to execute once in Windows:

wsl --shutdown

Then re-enter the distribution.

Method B: systemd Not Enabled

If you haven't enabled systemd, you can start manually first:

sudo service ssh start
sudo service ssh status

This approach also works, but note: after the WSL distribution exits, the service usually won't persist like a traditional Linux server.

5. Verify Windows Local Access First

Do a local test in Windows PowerShell first:

ssh <your_user>@localhost

As long as this step doesn't work, don't proceed with LAN port forwarding. The portproxy only forwards requests to WSL -- it cannot solve SSH issues inside WSL itself.

If you are using a non-standard port:

ssh <your_user>@localhost -p <port>

6. Allow Other LAN Machines to Access WSL

By default, other LAN devices cannot stably access WSL directly. The more reliable approach is:

  1. Open a listening port on Windows
  2. Forward that port to the SSH port of the current WSL instance

6.1 Get the Current WSL IP

Execute in an elevated PowerShell:

$distro = "Ubuntu"
$wslIp = wsl -d $distro -- bash -lc "hostname -I | awk '{print \$1}'"
$wslIp

Change $distro to your distribution name.

6.2 Add Windows Firewall Rule

Still in an elevated PowerShell:

New-NetFirewallRule `
-DisplayName "WSL SSH 22" `
-Direction Inbound `
-Action Allow `
-Protocol TCP `
-LocalPort 22

If you plan to forward to a different port, replace 22 with your listening port.

6.3 Configure portproxy

Clear old rules first, then re-add:

netsh interface portproxy delete v4tov4 listenaddress=0.0.0.0 listenport=22
netsh interface portproxy add v4tov4 listenaddress=0.0.0.0 listenport=22 connectaddress=$wslIp connectport=22

View current rules:

netsh interface portproxy show all

The meaning here is:

  • Windows listens on 0.0.0.0:22
  • When a connection is received, it forwards to port 22 of the current WSL IP

6.4 Connect from Another Machine

First find the Windows host's IP on the LAN:

ipconfig

Then on another machine:

ssh <your_user>@<windows_lan_ip>

If the Windows listening port is not 22, don't forget to add -p.

7. What to Do When the WSL IP Changes

This is the most common pitfall of portproxy. After WSL restart, Windows restart, or network environment changes, the WSL IP may change.

So once you find:

  • ssh user@localhost still works
  • But ssh user@<windows_lan_ip> suddenly doesn't work

First suspect that portproxy is still pointing to the old WSL IP. The most direct fix is to re-execute the steps from the previous section to get the IP and add portproxy rules.

Minimal Troubleshooting Order

It is recommended to troubleshoot in this order, rather than starting by modifying the firewall:

  1. In WSL: sudo service ssh status or sudo systemctl status ssh
  2. In WSL: ss -lntp | grep :22
  3. On Windows: ssh <your_user>@localhost
  4. On Windows: Test-NetConnection -ComputerName localhost -Port 22
  5. Check netsh interface portproxy show all
  6. Then check Windows firewall and LAN IP

Frequently Asked Questions

1. Why Not Enable Root Login by Default

Although WSL is often used as a local development environment, as soon as you open LAN access, it becomes a truly exposed SSH service on the network. The habit of using a normal user with sudo is much safer.

2. service ssh start Succeeded, But It's Gone After Reopening WSL

This is usually not SSH being broken, but the service not persisting after the WSL instance exits. Either accept "start manually when needed," or switch to enabling systemd.

3. Why chmod 600 /etc/ssh/sshd_config Is Not the Focus of Troubleshooting

Many tutorials will have you change this permission right away, but the actually more common problems are:

  • Service not started
  • authorized_keys permissions are wrong
  • portproxy pointing to an old IP
  • Windows firewall not allowing the connection

Further Reading