GitHub - sakai135/wsl-vpnkit: Provides network connectivity to WSL 2 when blocked by VPN

GitHub

6 min read Original article ↗

wsl-vpnkit provides network connectivity for WSL 2 when your Windows VPN blocks access. It requires no changes to Windows settings or administrator privileges on the Windows host.

For previous versions, see v0.3 and v0.2.

Setup

Before setting up wsl-vpnkit, try ping 1.2.3.4 inside WSL 2. If the ping succeeds, follow the steps in WSL has no network connectivity once connected to a VPN instead. WSL 2 networking options like mirrored mode and other .wslconfig options may resolve the issue as well.

wsl-vpnkit is intended for cases where those options do not work.

Option A: install wsl-vpnkit as a distro

Download wsl-vpnkit-amd64.wsl (or wsl-vpnkit-arm64.wsl for ARM64) from the latest release and open it to import the distro into WSL 2. This option lets you start wsl-vpnkit even when your existing WSL distro has no network connectivity.

Run the following command to start wsl-vpnkit in the foreground.

wsl.exe -d wsl-vpnkit --cd /app wsl-vpnkit

Setup systemd

You can optionally use systemd to start wsl-vpnkit when your WSL 2 distro starts. Create the service file in your existing WSL 2 distro and enable the service.

# copy the service file from wsl-vpnkit to your distro
wsl.exe -d wsl-vpnkit --cd /app cat /app/wsl-vpnkit.service | sudo tee /etc/systemd/system/wsl-vpnkit.service

sudo systemctl enable wsl-vpnkit
sudo systemctl start wsl-vpnkit
systemctl status wsl-vpnkit

Update

To update, unregister the existing wsl-vpnkit distro and open the new wsl-vpnkit.wsl to import the new version.

wsl.exe --unregister wsl-vpnkit

Option B: install as a standalone script

The wsl-vpnkit script can be installed and run in your existing distro. The following is an example setup script for Ubuntu.

# install dependencies
sudo apt-get install iproute2 iptables iputils-ping dnsutils curl jq yq

# download wsl-vpnkit and unpack
curl -fL https://github.com/sakai135/wsl-vpnkit/releases/latest/download/wsl-vpnkit-amd64.wsl -o wsl-vpnkit.wsl
tar --strip-components=1 -xf wsl-vpnkit.wsl app/wsl-vpnkit app/wsl-vpnkit.yaml app/wsl-gvproxy.exe app/wsl-vm app/wsl-vpnkit.service
rm wsl-vpnkit.wsl
sudo mv wsl-vpnkit wsl-gvproxy.exe wsl-vm /usr/local/bin/

# run the wsl-vpnkit script in the foreground
sudo wsl-vpnkit

# optionally setup systemd
sudo mv ./wsl-vpnkit.service /etc/systemd/system/
sudo systemctl enable wsl-vpnkit
sudo systemctl start wsl-vpnkit
systemctl status wsl-vpnkit

Configuration

Environment variables

The wsl-vpnkit script supports the following environment variables. For the full list, see the wsl-vpnkit script.

Variable (default value) Description
DEBUG (0) Enables debug output when set to 1.
CHECK_HOST (host.containers.internal) Host name used by startup DNS diagnostics.
GVPROXY_PATH (wsl-gvproxy.exe from PATH) Path to the wsl-gvproxy.exe executable.
VMEXEC_PATH (wsl-vm from PATH) Path to the wsl-vm executable.
WSL2_GATEWAY_IP (detected from the default route or resolver configuration) WSL 2 gateway IP address.
WSL2_TAP_NAME (detected route interface or eth0) WSL 2 interface used to restore the default route.
GVPROXY_CONFIG (disabled) Path to a gvproxy YAML configuration file. Requires yq.
PREEXISTING (1) When 1, wsl-vpnkit creates and configures a TAP interface. When 0, wsl-vm creates the interface and configures it with DHCP.

Config file

The repository includes wsl-vpnkit.yaml as an example config file to use with GVPROXY_CONFIG.

sudo GVPROXY_CONFIG=/path/to/config.yaml PREEXISTING=0 wsl-vpnkit

Troubleshooting

Using WSL release prior to 2.4.4

Support for importing .wsl distro files was added in WSL release 2.4.4. If you are using an older release of WSL, this command will import the downloaded distro.

$env:USERPROFILE\wsl-vpnkit is the destination folder. Replace wsl-vpnkit.wsl with the path to the downloaded file.

# PowerShell

wsl --import wsl-vpnkit "$env:USERPROFILE\wsl-vpnkit" wsl-vpnkit.wsl --version 2

Error messages from wsl-vpnkit

resolv.conf has been modified without setting generateResolvConf

wsl-vpnkit normally uses /mnt/wsl/resolv.conf to get the WSL 2 gateway IP. If you modify /etc/resolv.conf to set a custom DNS configuration, set generateResolvConf=false in wsl.conf.

On older WSL versions where /mnt/wsl/resolv.conf is not available, wsl-vpnkit will fall back to using /etc/resolv.conf. When set up as a standalone script and using a custom DNS configuration for the distro, the WSL2_GATEWAY_IP environment variable should be set for wsl-vpnkit to use.

wsl-gvproxy.exe is not executable due to WSL interop settings or Windows permissions

wsl-vpnkit requires the WSL 2 distro to be able to run Windows executables. The interop setting is enabled by default in WSL 2 and in the wsl-vpnkit distro.

If you see cannot execute binary file: Exec format error, check whether /usr/lib/binfmt.d/WSLInterop.conf exists. If it does not, generate it and restart the related service.

sudo sh -c 'echo :WSLInterop:M::MZ::/init:PF > /usr/lib/binfmt.d/WSLInterop.conf'
sudo systemctl restart systemd-binfmt

Security configurations on the Windows host may only permit running executables in certain directories. You can copy wsl-gvproxy.exe to an appropriate location and use the GVPROXY_PATH environment variable to specify the location.

# enable [automount] in wsl.conf for wsl-vpnkit distro
wsl.exe -d wsl-vpnkit --cd /app sed -i -- "s/enabled=false/enabled=true/" /etc/wsl.conf

# set GVPROXY_PATH when running wsl-vpnkit
wsl.exe -d wsl-vpnkit --cd /app GVPROXY_PATH=/mnt/c/path/wsl-gvproxy.exe wsl-vpnkit

Configure VS Code Remote WSL Extension

If VS Code takes a long time to open your folder in WSL, enable the setting "Connect Through Localhost".

Try shutting down WSL 2 VM to reset

# PowerShell

# shutdown WSL to reset networking state
wsl --shutdown

# kill any straggler wsl-gvproxy processes
kill -Name wsl-gvproxy

Run service with debug

# set the DEBUG environment variable
wsl.exe -d wsl-vpnkit --cd /app DEBUG=1 wsl-vpnkit

Notes

Build

The core changes wsl-vpnkit made to gvisor-tap-vsock were upstreamed back to gvisor-tap-vsock. wsl-vpnkit v0.4 is a set of configurations and a shell script to execute the binaries from gvisor-tap-vsock.

The Alpine build is used to package everything into one WSL 2 distro export. The Fedora and Ubuntu builds are for validating the script in different distros. Builds produce a wsl-vpnkit.wsl file for the host architecture.

# build with alpine image to ./wsl-vpnkit.wsl
./build.sh alpine

# build with fedora using Podman
DOCKER=podman ./build.sh fedora

# import the built distro from ./wsl-vpnkit.wsl
./import.sh

# run using the imported distro
wsl.exe -d wsl-vpnkit --cd /app wsl-vpnkit

Tests

The test suite runs the wsl-vpnkit script in a privileged Docker container using real and mock binaries.