Post

Port forwarding Between Windows and WSL2

Port forwarding Between Windows and WSL2

Background

I was setting up Docker containers in WSL2 and wanted to access a self-hosted web service from my local network but was unable to connect to it. After speaking with my mentor, he showed me that it was because WSL2 required port forwarding.

By default, WSL2 has “a virtualized ethernet adapter with its own unique IP address” (Microsoft Learn). This virtual ethernet adapter is hidden behind NAT, Network Address Translation, which is why it needs port forwarding to make its services reachable (jwstanley).

Identifying IP Address

Bash command to see ethernet IP address in WSL2 Linux distro:

1
ip addr | grep eth0

This command pipes | the ip addr command into grep, which performs a text search for eth0. eth0 is the name of the virtualized ethernet adapter in WSL2.

Example output:

2: eth0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc mq state UP group default qlen 1000 inet 172.17.110.111/20 brd 172.17.111.255 scope global eth0

172.17.110.111 would be the WSL2 IP address that we’re looking for.

Port Forwarding with Powershell Command

1
netsh interface portproxy add v4tov4 listenport=<yourPortToForward> listenaddress=0.0.0.0 connectport=<yourPortToConnectToInWSL> connectaddress=<wsl2IPAddress>
  • netsh interface portproxy add v4tov4 - creates a new port forwarding rule for listening and forwarding between two IPv4 addresses.
  • listenport=<yourPortToForward> - specifies which port on the local machine that will listen for incoming connections.
  • listenaddress=0.0.0.0 - tells the system which IP address to listen for.
    • 0.0.0.0 - a wild card IP address that allows the proxy to accept connections from any network interface on the Windows host machine.
    • Since the service I was hosting is only available locally, external devices can only access it if they are on the same local network as the host machine.
  • connectport=<yourPortToConnectToInWSL> - port that traffic will be forwarded to on the destination machine. In this case, its the WSL2 virtual machine.
  • connectaddress=<wsl2IPAddress> - IP address of the destination machine.
    • (wsl hostname -I) can replace <wsl2IpAddress> to automatically retrieve the IP address.

Example Command

1
netsh interface portproxy add v4tov4 listenport=3000 listenaddress=0.0.0.0 connectport=3000 connectaddress=172.17.110.111

In short, this allows any connection on the host machine’s IP address (listenaddress=0.0.0.0) received on port 3000 (listenport=3000) to be forwarded to the IP address 172.17.110.111 on the same port (connectport=3000).

For example, if the host machine’s private IP address is 192.168.254.11, connecting to 192.168.254.11:3000 on an external device would forward that port to the web service hosted on 172.17.110.11:3000 inside of WSL2.

With this command, it achieves our goal of having the WSL2 service on port 3000 be reachable from outside the WSL2 virtual machine.

Keep in mind that this only makes the WSL2 service open to external devices that are on the same local network, not the entire internet.

Powershell command to see all forwarded ports:

1
netsh interface portproxy show v4tov4

Example output

Listen on ipv4: Connect to ipv4: 
AddressPortAddressPort
0.0.0.03000172.17.110.113000

I created a diagram to illustrate the points above so we can visualize how the port forwarding works.

Diagram

WSL2-Port-Forwarding-drawio.png

Update: I edited the diagram to be less vague and to represent the infrastructure by having the WSL2 instance inside of the Windows PC. Tool used: Draw.io

Automating WSL2 Firewall Rules and Port Forwarding

If the IP address of the destination machine changes, you would have to add the Powershell command every time.

Firewall rules are another consideration to take into account as Windows firewall may automatically block the ports you want to forward.

Luckily, github user edwindijas shared a Powershell script that automates updating the port forwarding rules and the firewall rules. (Source)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33

$remoteport = bash.exe -c "ifconfig eth0 | grep 'inet '"
$found = $remoteport -match '\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}';

if( $found ){
  $remoteport = $matches[0];
} else{
  echo "The Script Exited, the ip address of WSL 2 cannot be found";
  exit;
}

#[Ports]

#All the ports you want to forward separated by coma
$ports=@(80,443,10000,3000,5000);

#[Static ip]
#You can change the addr to your ip config to listen to a specific address
$addr='0.0.0.0';
$ports_a = $ports -join ",";

#Remove Firewall Exception Rules
iex "Remove-NetFireWallRule -DisplayName 'WSL 2 Firewall Unlock' ";

#adding Exception Rules for inbound and outbound Rules
iex "New-NetFireWallRule -DisplayName 'WSL 2 Firewall Unlock' -Direction Outbound -LocalPort $ports_a -Action Allow -Protocol TCP";
iex "New-NetFireWallRule -DisplayName 'WSL 2 Firewall Unlock' -Direction Inbound -LocalPort $ports_a -Action Allow -Protocol TCP";

for( $i = 0; $i -lt $ports.length; $i++ ){
  $port = $ports[$i];
  iex "netsh interface portproxy delete v4tov4 listenport=$port listenaddress=$addr";
  iex "netsh interface portproxy add v4tov4 listenport=$port listenaddress=$addr connectport=$port connectaddress=$remoteport";
}

Alternative Solution - Mirrored Mode

Another solution to making WSL2 servers accessible from your local network is to create a .wslconfig file and set networkingMode=mirrored.

This mode replaces the default NAT setting by having all Windows network interfaces mirrored onto the Linux distributions in WSL2. Network services between Windows and WSL2 can now be accessed seamlessly without setting up port forwarding.

Warning: mirrored networking mode in WSL2 is an experimental setting that may have bugs and limitations

Although using mirrored mode makes the networking more streamlined, I found it helpful to set up port forwarding first to better familiarize myself with the concept. Through either port forwarding or using mirrored mode, my self-hosted Docker services in WSL2 are made available through my local network.

Glossary

  • WSL2 - Windows Subsystem for Linux 2, a tool that allows Windows users to “run Linux distributions as isolated containers inside a lightweight virtual machine” (Microsoft Learn)
  • port - a number that identifies a specific process or a type of network service (e.g. Port 80 for requesting web pages from a web server). This number is used to direct data to a specific service (Wikipedia)
  • port forwarding - a network configuration setting that allows external devices to access specific services on a private network by directing incoming traffic on a particular port number to a specific device within that network
  • network interface - the point of interconnection between a computer and a private or public network (Oracle).
    • Can be hardware (network cards) or software (virtual machines)
    • Each network interface has its own unique IP address

Sources

This post is licensed under CC BY 4.0 by the author.