I am a big fan of WSL. One of my biggest complaints about WSL2 (mainly on principle) is that it does not support IPv6. But with a bit of tweaking, we can make it work.

Approach 1: WireGuard

We will use an IPv6 tunnelbroker. WireGuard makes this easy.

  1. Check the kernel. In WSL, run uname -srm to check the kernel version. Kernels since 5.6 include WireGuard. If you have an older kernel, see how to replace the kernel below.

  2. Install WireGuard. Run sudo apt install wireguard.

  3. Create a tunnel. Create an account at route48.org. Create a new IPv6 tunnel. Set the tunnel type to WireGuard and pick a server location near you. Click the config icon and copy the configuration into /etc/wireguard/wg0.conf. Run sudo wg-quick up wg0 to start the tunnel.

  4. Connect. Test your connection with ping6 google.com. It should work now.

  5. Start automatically. Edit /etc/wsl.conf to contain

    command="wg-quick up wg0"

    This will start the tunnel every time the WSL instance starts. The [boot] option is new in Windows 11.

Approach 2: Tailscale

Tailscale is magic. We can share another device’s IPv6 connection with Tailscale.

  1. Create an exit node. Install Tailscale on a device with an IPv6 connection. This might even be your Windows machine. Configure it as an exit node. Save its Tailscale IP address (100.x.y.z) for later.

  2. Start Tailscale automatically. Install Tailscale in WSL. Edit /etc/wsl.conf to contain
    command="PATH=$PATH tailscaled"

    This will start tailscaled every time the WSL instance starts.

  3. Update the kernel. Tailscale needs CONFIG_IPV6_MULTIPLE_TABLES, so we have to build the kernel. (If you trust me, you can download my kernel.) Clone the WSL2 kernel. Add a line CONFIG_IPV6_MULTIPLE_TABLES=y to Microsoft/config-wsl, and edit the CONFIG_LOCALVERSION line with a name you will recognize later. Follow the build instructions in the README. Download/copy vmlinux to C:\vmlinux. Create a file %UserProfile%\.wslconfig containing

    (Note the double backslashes in the path.)

  4. Restart WSL. Run wsl.exe --shutdown. Check that no WSL2 distros are running with wsl.exe -l -v. Then restart WSL and run uname -srm to check that the new kernel is running. It should have the version string you set in the config file.

  5. Route traffic through the exit node. Check that tailscaled is running with ps aux. Run sudo tailscale up --exit-node=100.x.y.z --exit-node-allow-lan-access, replacing 100.x.y.z with the exit node’s IP address from above.

  6. Connect. Test your connection with ping6 google.com. It should work now.

Update 2022-10-21:

WSL supports systemd starting in version 0.67.6. Enable systemd by adding systemd=true in the [boot] section of /etc/wsl.conf instead of specifying boot commands. Configure systemd to start the WireGuard interface with sudo systemctl enable wg-quick@wg0. Tailscale should start automatically when systemd is enabled.

IPv6 requires at least MTU 1280, but wg-quick now sets the MTU to 1200 on my system. To configure the WireGuard interface MTU, add a line MTU = 1280 in the [Interface] section of /etc/wireguard/wg0.conf.

Update 2023-03-30:

Route48 is no longer providing tunnels. route64.org is an alternative.