26

I am running an SSH server within WSL2 on a WIN10 machine. To make that work I am using:

netsh interface portproxy add v4tov4 listenaddress=0.0.0.0 listenport=22 connectaddress=172.19.237.178 connectport=22

This works fine initially. 172.19.237.178 is the IP of the WSL2 VM.

There is just one problem. I have the sshd set to run when the PC boots, and every time I boot the machine WSL2 has a different IP. Is there any way to configure WSL2 to use a static IP?

Edit: See this question for a workaround to determine the WSL machine's IP.

2
  • I just took a look through this GitHub issue thread about people having the same issue as you. Looks like it's just not supported right now. It looks like some people on that thread were able to get results that were acceptable by forwarding some of the VM's ports to the host, but that may not work in your situation.
    – Sam Forbis
    Sep 1, 2020 at 14:46
  • @SamForbis I saw the same thread, and agree, I don't think the workaround will do what I need. I am trying to write scripts to RSYNC files from a remote computer into WSL.A workaround might be to determine when WSL has booted, figure out its IP, and then do the routing. The host's IP is static, so if I could just make the v4tov4 routing always work at boot then it doesn't matter that WSL's IP isn't static.
    – Nick
    Sep 1, 2020 at 17:11

9 Answers 9

21

The IP address of a WSL2 machine cannot be made static, however it can be determined using wsl hostname -I

Based on this I was able to create the following powershell script that will start sshd on my WSL machine and route traffic to it.

wsl.exe sudo /etc/init.d/ssh start
$wsl_ip = (wsl hostname -I).trim()
Write-Host "WSL Machine IP: ""$wsl_ip"""
netsh interface portproxy add v4tov4 listenport=22 connectport=22 connectaddress=$wsl_ip

I added the following to my sudoers file via visudo to avoid needing a password to start sshd

%sudo ALL=(ALL) NOPASSWD: /etc/init.d/ssh

Finally, from an administrative powershell terminal, I scheduled my script to run at startup

$trigger = New-JobTrigger -AtStartup -RandomDelay 00:00:15
Register-ScheduledJob -Trigger $trigger -FilePath C:\route_ssh_to_wsl.ps1 -Name RouteSSHtoWSL
7
  • Why don't we use set v4tov4 instead of add v4tov4?
    – Hunkoys
    Oct 29, 2021 at 18:34
  • I didn't think to try it. Is there an advantage to using set rather than add? I'm always running this script at startup so there are no existing portproxies when I run it so I never encounter an issue with using add.
    – Nick
    Nov 2, 2021 at 13:50
  • @Nick Hello sir, your answer was really helpful to me. It got me closer to what I'm looking for, but I haven't been able to completely solve my problem yet. I won't mind if you could help me take a look at this question that I posted over here superuser.com/questions/1685689/…
    – Ikechukwu
    Nov 5, 2021 at 7:26
  • 1
    @Nick I just thought add might actually create a new set of rules everytime the ip changes. I haven't tried add though, so I can't prove it. set seems to work. It updates existing rules.
    – Hunkoys
    Nov 10, 2021 at 5:49
  • Thanks to an upvote of my answer I can now comment, this answer is almost good for me, except wsl hostname -I returns two IP ("IP1 IP2") and I want first one, I then do: $wsl_ip = (wsl hostname -I).split(" ")[0]
    – gluttony
    Jun 16, 2022 at 9:20
9

This solution helped me to set up a static ip of my wsl, try:

Run this on your windows host machine:

netsh interface ip add address "vEthernet (WSL)" 192.168.99.1 255.255.255.0

And this on your wsl linux machine:

sudo ip addr add 192.168.99.2/24 broadcast 192.168.99.255 dev eth0 label eth0:1;

But to keep this IP after the rebooting your sytem you need to set up those commands in the startup scrip.

4
  • 2
    This is perfect. This solved my problem. Thank you.
    – Rahmani
    Jul 17, 2022 at 17:18
  • How do you run a sudo command on bootup inside WSL? For netsh I found social.technet.microsoft.com/Forums/office/en-US/…
    – chx
    Sep 15, 2022 at 18:28
  • Hm, It just works inside my WSL) And netsh works on windows too (if you launch cmd like an Admin user) Sep 18, 2022 at 17:20
  • Answer: wsl.exe -u root. Last line of my .zshrc: wsl.exe -u root service mysql status >/dev/null || wsl.exe -u root /etc/rc.local where rc.local starts mysql, apache, redis and adds this IP address.
    – chx
    Oct 25, 2022 at 6:54
3

No need to use scripts to get the ip, just use Openssh server for windows and change the default shell from c:/system32/cmd.exe to c:/system32/bash.exe:

https://docs.microsoft.com/en-US/windows-server/administration/openssh/openssh_server_configuration

2
  • Would I be able to SCP and Rsync files into the WSL2 file system area just the same with the windows SSH server?
    – Nick
    May 19, 2021 at 3:46
  • Rsync work like a charm for me. I think SCP will work too. May 25, 2021 at 13:33
2

Using wsl and wsl2 at the same time caused problems for me. Could not get correct wsl hostname from the powershell command:

wsl hostname -I

Building on the answer from Nick, I needed to forward web 80 and 443, along with some other app ports.

ubuntu2004.exe -c "sudo /etc/init.d/ssh start"
$wsl_ip = (ubuntu2004.exe -c "ifconfig eth0 | grep 'inet '").trim().split()| where {$_}
$regex = [regex] "\b(?:(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.){3}(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\b"

$ip_array = $regex.Matches($wsl_ip) | %{ $_.value }

$wsl_ip = $ip_array[0]

Write-Host "WSL Machine IP: ""$wsl_ip"""

netsh interface portproxy add v4tov4 listenport=443 listenaddress=0.0.0.0 connectport=443 connectaddress=$wsl_ip
netsh interface portproxy add v4tov4 listenport=8080 listenaddress=0.0.0.0 connectport=8080 connectaddress=$wsl_ip
netsh interface portproxy add v4tov4 listenport=80 listenaddress=0.0.0.0 connectport=80 connectaddress=$wsl_ip
netsh interface portproxy add v4tov4 listenport=3001 listenaddress=0.0.0.0 connectport=3001 connectaddress=$wsl_ip
netsh interface portproxy add v4tov4 listenport=2222 listenaddress=0.0.0.0 connectport=2222 connectaddress=$wsl_ip
netsh interface portproxy add v4tov4 listenport=22 listenaddress=0.0.0.0 connectport=22 connectaddress=$wsl_ip
1
  • Nice, thanks for sharing. You might be able to get rid of the regex if you do some cutting in the bash command. But then again, if the output of ifconfig changes this will break. bash -c "ifconfig eth0 | grep 'inet ' | cut -d ' ' -f 10"
    – Nick
    Feb 15, 2021 at 20:56
1

I have not enough reputation to comment then I put my own answer but approved answer by Nick (https://superuser.com/a/1619390/1023342) is the good one for me, expect for one small detail, for me wsl hostname -I returns two IP ("IP1 IP2") and I want first one, I then do:

$wsl_ip = (wsl hostname -I).split(" ")[0]
netsh interface portproxy add v4tov4 listenport=22 connectport=22 connectaddress=$wsl_ip
1

A no-brainer solution, I run this script manually(run as administrator) everytime I need to proxy a port to WSL.

proxyport.bat

wsl hostname -I
@echo off
set /p WSLIP=What is the current WSL IP address?
netsh interface portproxy add v4tov4 listenaddress=0.0.0.0 listenport=2222 connectaddress=%WSLIP% connectport=2222

Then one more step in the WSL terminal:

sudo service ssh start
2
  • 1
    If you take a part of my powershell script: $wsl_ip = (wsl hostname -I).trim() netsh interface portproxy add v4tov4 listenport=22 connectport=22 connectaddress=$wsl_ip It will do the same thing as your batch file, but it will automate the step of reading/writing the IP address. You can still run it manually as an administrator. Just call it portproxy.ps1.
    – Nick
    Dec 8, 2021 at 15:13
  • @Nick, I worked your quick trim into the script I use, it also deals with the firewall if you have that need: gist.github.com/axonxorz/612865c294df5b87ced06fc2717c1ffc
    – axon
    Dec 13, 2021 at 17:50
0

Here's a very compact solution for WSL2 that will auto-start the SSH server. It eliminates having to deal with Powershell signing/execution policies and having to run it on a schedule.

  1. Run wsl sudo nano /etc/wsl.conf and add these lines:

    [boot]
    command="service ssh start"
    

    This will auto-start SSH server on every WSL startup.

  2. (Optional) If you'd like to use a custom port (like 2022) for SSH (for example, if you use multiple WSL distros), run:

    wsl sudo sed -i 's|.*Port.*|Port 2022|' /etc/ssh/sshd_config
    

This works because WSL2 maps ports from its distros to the Windows' localhost. Now you can just connect to your host using localhost:22 (or a custom port).

0

I've insignificantly improved the script in Nick's answer because i needed to wait for docker desktop started, so here it is:

while ($true) {
    $wsl_ip = (wsl hostname -I).trim()
    $regex = [regex]"\b\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}\b"
    if ($regex.IsMatch($wsl_ip)) {
        Write-Host "IP Address: $wsl_ip"
        break
    }
    else {
        Write-Host "Invalid IP Address"
        Start-Sleep -Seconds 10
    }
}
netsh interface portproxy add v4tov4 listenport=2222 connectport=2222 connectaddress=$wsl_ip
-1
  1. Start wsl

  2. En terminal (wsl)

    sudo ifconfig eth0 172.27.100.100 netmask 255.255.255.0 broadcast 172.27.255.255

  3. En Powershell

    netsh interface ip set address name="vEthernet (WSL)" static 172.27.100.99 255.255.255.0 172.27.255.255

Access to wls to windows 172.27.100.99 Access to windows to wls 172.27.100.100

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge that you have read and understand our privacy policy and code of conduct.

Not the answer you're looking for? Browse other questions tagged or ask your own question.