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
Symptoms
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 1.1.1.1 -c 1
from WSL:
PING 1.1.1.1 (1.1.1.1) 56(84) bytes of data.
--- 1.1.1.1 ping statistics ---
1 packets transmitted, 0 received, 100% packet loss, time 0ms
In the example we can see that no response is received from 1.1.1.1 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 ifIndex
of 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?
Solutions
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 Fix
and 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.net
with 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:
Program:C:\Windows\System32\WindowsPowerShell\v1.0\powershell.exe
Arguments:-f C:\utilities\fixroutes.ps1
Start in:C:\utilities
- Uncheck
Start the task only if the computer is on AC power
in the Conditions tab - Create the task and manually run it to verify functionality
DNS Resolution Failure
Symptoms
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.
Solution
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 1.1.1.1\nnameserver 1.0.0.1" | 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.
3 replies on “WSL 2 and VPN Woes”
Hi Mate! Arrived here via google searching for a solution for the lack of connectivity in WSL2 when connected to my VPN. Following your instructions I get:
(OUTSIDE VPN):
Get-NetIpAddress -InterfaceAlias "vEthernet (WSL)" | Format-Table -Property ifIndex,IPAddress
ifIndex IPAddress
------- ---------
69 fe80::a875:39f6:1803:6561%69
69 172.28.96.1
Get-NetRoute -DestinationPrefix 172.28.96.0* | Format-Table -AutoSize
ifIndex DestinationPrefix NextHop RouteMetric ifMetric PolicyStore
------- ----------------- ------- ----------- -------- -----------
69 172.28.96.0/20 0.0.0.0 256 15 ActiveStore
(INSIDE VPN)
The first command outputs the same, but the second doesn’t output anything.
Inside VPN nothing connects:
ping www.google.com.ar
ping: www.google.com.ar: Temporary failure in name resolution
Do you have any idea how to resolve it?
I don´t know what else to try… 🙁
From what you’re saying it sounds like you do not even have a route to the WSL network after connecting to your VPN. Have you tried manually adding the 172.28.96.0/20 route back into the routing table after connecting to the VPN to see if that resolves the issue?
Regarding “WSL 2 VPN Routing Fix Script” I tried removing the route but it keeps reappearing immediately in the table, even when i. e. route delete 172.23.103.0 mask 255.255.240.0 metric 2 IF 5