I have read many articles about WSL networking that try and sort DNAT and static IP and none that I've found seem to work or only work for some. So here is my attempt....
It seems getting port forwarding to work in WSL is not easy. I think WSL has unusual hidden network mechanisms and that confuses the matter. Also when WSL boots the WSL init mechanism gives the guest a random address, which is no use for static NAT
This worked for me. Try it yourself and let me know if I've finally cracked it !!
Find WSL the subnet matched to a Hyper-V Virtual Ethernet/Virtual Switch IP subnet, we need to find the name of that switch later.
C:\> Get-ItemProperty -path HKLM:\system\CurrentControlSet\Services\Tcpip\Parameters -name IPEnablerouter
C:\> Set-ItemProperty -path HKLM:\system\CurrentControlset\services\Tcpip\parameters -name IPEnablerouter -Value 1
Edit C:\users\\<username>\.wslconfig
Turn off default setting that (fails) to forward ports to WSL unless they come from localhost.
[wsl2]
LocalHostForwarding=false
=>> NOTE: LocalHostForwarding = 'true' seems to block all attempts to alter NAT
.... but on a different IP, otherwise WSL may revert settings!
C:\> Get-NetAdapter
=>> Note the name, something like "vEthernet (WSL)"
C:\> Get-NetIPAddress
=>> Find the IP address with the same interface name "vEthernet (WSL)"
You should see something like 172.x.y.z/m
=>> Choose a subnet so there are no collisions, I will use 192.168.160.0/28.
C:\> New-NetIPAddress -IPAddress 192.168.160.1 -PrefixLength 28 -InterfaceAlias "vEthernet (WSL)"
C:\> Get-NetNatExternalAddress
=>> Note NAT "Name" attached to the external IP for me that was = "wsl-nat"
C:\> New-NetNat -name "wsl-nat" -InternalIPInterfaceAddressPrefix "192.168.160.1/28"
C:\> Add-NetNatStaticMapping -ExternalIPAddress "0.0.0.0/0" -ExternalPort 22 -InternalIPAddress 192.168.160.10 -InternalPort 22 -NatName "wsl-nat" -Protocol tcp
=>> Like most of PowerShell this will either work or return a meaningless large red box message which may as well read "The computer says NO!"
(Perhaps check this sooner)
4a: Ensure the firewall in Windows allows incoming connections on port 22 on the external interface from an appropriate source network
4b: Ensure you don't have another ssh service already running on port 22 on the external interface
C:\> Get-NetTCPConnection -LocalPort 22
=>> This should return no existing listening ports. If this is not the case find the process id - it will most likely be another running WSL or an open-ssh Windows System service. Shutdown WSL and/or stop the service (or use a port other than 22)
user@WSL:~$ sudo ip address list
=>> You should see an address like 172.x.y.z
as seen above on device eth0
user@WSL:~$ sudo ip address add 192.168.160.10/28 dev eth0
=>> DONE!
You should now be able to access ssh from another device on the same routable IP network.
As I am on Ubuntu-WSL-23.04 I will use netplan.
NOTE: The DNS addresses come from whatever Windows has or you could use one or more of 8.8.8.8, 8.8.4.4, 1.1.1.[1|2|3]
C:\> Get-DnsClientServerAddress
Edit /etc/netplan/01-netcfg.yaml
# /etc/netplan/01-netcfg.yaml
network:
ethernets:
eth0:
dhcp4: false
optional: false
addresses: [192.168.160.10/28]
nameservers:
addresses: \[1.1.1.1,8.8.8.8]
search: [local,localdomain,lan]
dhcp6: false
version: 2
renderer: networkd
=>> Final test: Logout, shutdown WSL and re-start and see if it's still works!
Okay, I don't know why this is working, but this is working:
New-NetIPAddress -IPAddress 192.168.160.1 -PrefixLength 28 -InterfaceAlias "vEthernet (WSL)"
command after reboot.sudo netplan apply
SSH to the WSL box --> it works. I have no idea why this wasn't working before...
Thank you so much, @the-moog! You are an absolute lifesaver.