Skip to content

Instantly share code, notes, and snippets.

@the-moog
Created June 6, 2023 19:48
Show Gist options
  • Save the-moog/e7a1b5150ce9017309afbcf91848e622 to your computer and use it in GitHub Desktop.
Save the-moog/e7a1b5150ce9017309afbcf91848e622 to your computer and use it in GitHub Desktop.
Make WSL2 networking play nicely with DNAT/dest-NAT/portproxy and/or give WSL a static IP address

Port forwarding from host (aka WSL2 Static IP)

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 !!

0: Understand currently setup.

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.

1: Enable routing in the registry

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

2: Disable forward ports

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

3: Setup DestNAT

.... 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!"

4: Firewall

(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)

4: Configure Linux (WSL)

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.

5: Make WSL permanent

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!

@Spartan1776
Copy link

Okay, I don't know why this is working, but this is working:

  1. Add the New-NetIPAddress -IPAddress 192.168.160.1 -PrefixLength 28 -InterfaceAlias "vEthernet (WSL)" command after reboot.
  2. DON'T run 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.

@Spartan1776
Copy link

@the-moog Did you have any thoughts on why New-NetIPAddress -IPAddress 192.168.160.1 -PrefixLength 28 -InterfaceAlias "vEthernet (WSL)" won't persist for me? If not, no worries, I'll just throw it in a script or something and have it execute on startup.

Thanks again!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment