Windows Subsystem for Linux (WSL) provides huge benefits to developers. It opens a whole world of Linux applications, improves your Docker performance, and lets you bash to your heart’s content. The Premier Developer blog at Microsoft has a glowing post about WSL with more of the details if you are so inclined.
Unfortunately, all of this functionality does not come without its troubles. Since switching to WSL 2, I have been unable to initiate any network connections within WSL when connected to my VPN. This is not a rare problem, but none of the existing issues on the WSL GitHub page worked for me.
This post details all of the solutions I tried and the one that finally worked.
Why Can’t I Connect?
After reading through the various issues others had posted, I’ve noticed two primary causes:
Network Routing Failure
When the issue is a network routing failure, you will notice all IP requests within WSL will time out and fail while networking will work as expected from Windows. You can test this by trying to ping a public IP using
ping 188.8.131.52 -c 1 from WSL:
PING 184.108.40.206 (220.127.116.11) 56(84) bytes of data. --- 18.104.22.168 ping statistics --- 1 packets transmitted, 0 received, 100% packet loss, time 0ms
In the example we can see that no response is received from 22.214.171.124 within WSL.
So what’s going on here? Let’s take a look at the Windows routing table.
First, find the WSL interface index and IP in PowerShell:
ifIndex IPAddress ------- --------- 49 172.23.48.1
Next, use the WSL interface IP you gathered to find routes for the WSL interface’s network. Replace the last octet of the WSL interface IP with 0 to match the network IP (
172.23.48.0 in this example):
ifIndex DestinationPrefix NextHop RouteMetric ifMetric PolicyStore ------- ----------------- ------- ----------- -------- ----------- 20 172.23.48.0/20 0.0.0.0 1 35 ActiveStore 49 172.23.48.0/20 0.0.0.0 256 5000 ActiveStore
Here we can see that there are two entries for the WSL network route. The route with an
20 uses the VPN interface in this scenario. Since it has a lower
ifMetric than the WSL interface (
35 < 5000), network requests to
172.23.48.0/20 will be routed through the VPN interface instead of the WSL interface. This is a problem!
WSL 2 uses a virtual network switch connected to an internal network to route requests between Windows and WSL. This means all requests will fail if Windows is attempting to route WSL traffic back through the VPN instead of routing through the internal network.
So now that we have an understanding of the problem, how can we solve it?
Change the VPN Interface Metric
Some people have been able to solve this issue by increasing the VPN interface metric. More information on how default Windows interface metrics are calculated can be found here.
The general idea is that you want to give the VPN interface a costlier metric than the WSL interface so that network traffic will prefer the WSL interface over the VPN interface.
Run PowerShell as an administrator and perform the following:
# Set the WSL network interface to the highest priority (1) Get-NetAdapter -Name "vEthernet (WSL)" | Set-NetIPInterface -InterfaceMetric 1 # Set the VPN network interface to a low priority (6000) # You can use Get-NetAdapter without arguments to try to find your VPN's description Get-NetAdapter -InterfaceDescription "Your VPN" | Set-NetIPInterface -InterfaceMetric 6000
Unfortunately, this approach did not work for me. While it did allow traffic out of WSL, I could no longer access internal network resources from Windows.
Delete the VPN Route for the WSL Gateway
The solution that worked for me was deleting the VPN route for the WSL gateway from the Windows routing table.
WSL 2 VPN Routing Fix Script
Here is the script that I used to perform the delete. You would need to replace
Ethernet 2 with the name of your VPN’s InterfaceAlias.
# Ensure WSL has been run as least once to start the WSL interface: wsl pwd # Gather the interfaces and current WSL network IP: $wsl = Get-NetIPInterface -InterfaceAlias "vEthernet (WSL)" -AddressFamily IPv4 $vpn = Get-NetIPInterface -InterfaceAlias "Ethernet 2" -AddressFamily IPv4 $ip = Get-NetIPAddress -InterfaceAlias "vEthernet (WSL)" -AddressFamily IPv4 $networkIp = "$($ip.IPAddress -replace "\.\d+$", ".0")" # Delete the associated VPN route Write-Output "Deleting route for $($networkIp) with index $($vpn.ifIndex)..." route delete $networkIp IF $vpn.ifIndex sleep 1 route delete $networkIp IF $vpn.ifIndex
Due to my particular VPN, the route needed to be deleted twice with a delay to take effect. This may not be necessary in all cases.
I also configured a scheduled task to run this script whenever the VPN was connected.
WSL 2 VPN Routing Fix Scheduled Task Creation
- Open Task Scheduler and create a new task
- Name the task
WSL 2 VPN Routing Fixand set it to run with highest privileges
- Create a new event trigger with a custom event type query with the following XML. Take care to replace
test.netwith your VPN network name.
<QueryList> <Query Id="0" Path="Microsoft-Windows-NetworkProfile/Operational"> <Select Path="Microsoft-Windows-NetworkProfile/Operational"> *[System[(EventID=10000)] and EventData[Data[@Name='Name'] and (Data='test.net')]] </Select> </Query> </QueryList>
- Create a new action with the following data:
Start the task only if the computer is on AC powerin the Conditions tab
- Create the task and manually run it to verify functionality
DNS Resolution Failure
When the issue is a DNS resolution failure, you will notice all hostname requests within WSL will time out and fail while networking will work as expected from Windows. Additionally, you will be able to make network requests by IP. You can test this by trying to resolve a DNS A record using
host google.com from WSL:
;; connection timed out; no servers could be reached
If you are receiving an error like the above instead of google’s IP address, you are experiencing this issue.
You can try replacing the default WSL 2 nameserver that points to your Windows WSL interface with the specific DNS servers that you would like to use for resolution with the following steps.
# Disable resolv.conf generation in WSL by editing /etc/wsl.conf: echo -e "[network]\ngenerateResolvConf=false" | sudo tee -a /etc/wsl.conf > /dev/null # Remove the current /etc/resolv.conf symlink sudo rm -f /etc/resolv.conf # Output your preferred nameservers into /etc/resolv.conf # You may find these with ipconfig /all in PowerShell. echo -e "nameserver 126.96.36.199\nnameserver 188.8.131.52" | sudo tee -a /etc/resolv.conf > /dev/null
At this point you should now be able to resolve DNS entries within WSL successfully.
If you have another WSL 2 VPN issue that was not listed here, please post a comment below.