WSL 2 and VPN Woes

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 -c 1 from WSL:

PING ( 56(84) bytes of data.

--- ping statistics ---
1 packets transmitted, 0 received, 100% packet loss, time 0ms

In the example we can see that no response is received from 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
------- ---------

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 ( in this example):

ifIndex DestinationPrefix NextHop     RouteMetric ifMetric PolicyStore
------- ----------------- -------     ----------- -------- -----------
20               1 35       ActiveStore
49             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 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.

Networking works between WSL and the WSL Gateway, but not between WSL and the VPN

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
  1. Open Task Scheduler and create a new task
  2. Name the task WSL 2 VPN Routing Fix and set it to run with highest privileges
  3. Create a new event trigger with a custom event type query with the following XML. Take care to replace with your VPN network name.
  <Query Id="0" Path="Microsoft-Windows-NetworkProfile/Operational">
    <Select Path="Microsoft-Windows-NetworkProfile/Operational">
      *[System[(EventID=10000)] and EventData[Data[@Name='Name'] and (Data='')]]
  1. 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
  2. Uncheck Start the task only if the computer is on AC power in the Conditions tab
  3. 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 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\nnameserver" | 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:
Get-NetIpAddress -InterfaceAlias "vEthernet (WSL)" | Format-Table -Property ifIndex,IPAddress

ifIndex IPAddress
------- ---------
69 fe80::a875:39f6:1803:6561%69

Get-NetRoute -DestinationPrefix* | Format-Table -AutoSize

ifIndex DestinationPrefix NextHop RouteMetric ifMetric PolicyStore
------- ----------------- ------- ----------- -------- -----------
69 256 15 ActiveStore

The first command outputs the same, but the second doesn’t output anything.
Inside VPN nothing connects:
ping: 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 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 mask metric 2 IF 5

Leave a Reply

Your email address will not be published. Required fields are marked *