🔐 Taming WSL in Bridged Mode with ProtonVPN and WireGuard
When you're routing traffic from a bridged WSL instance through a ProtonVPN WireGuard tunnel running on your Windows host, you're essentially building a hybrid between enterprise-grade routing and developer-friendly sandboxing. Here's how I untangled this setup and got it working beautifully—including pitfalls, commands, and how to make it persist across reboots.
🧠 Initial Symptoms
I started off by noticing that my WSL traffic wasn't tunneling through ProtonVPN:
curl ifconfig.io
>> 203.0.113.45 # Not the ProtonVPN exit IP
This meant that WSL (bridged mode) was bypassing the VPN tunnel and going out through the LAN directly.
🔧 Step-by-Step Fix
1. Route WSL Through Windows Host
Since my WSL IP is in the same subnet (10.254.1.x
) as the host:
ip route replace default via 10.254.1.60
This forced WSL to send its outbound traffic to the host.
2. Enable NAT on Windows
Windows doesn’t NAT bridged traffic by default. So I created a NAT rule:
New-NetNat -Name "WSLNat" -InternalIPInterfaceAddressPrefix 10.254.1.0/24
You can verify it with:
Get-NetNat
Boom—after applying this, WSL could finally reach public IPs through the host.
3. Fixing DNS Inside WSL
Originally I pointed DNS to my host:
echo "nameserver 10.254.1.60" | sudo tee /etc/resolv.conf
But it failed because the host wasn’t running a DNS forwarder. Instead, I switched to:
echo "nameserver 1.1.1.1" | sudo tee /etc/resolv.conf
sudo chattr +i /etc/resolv.conf
Locking the file ensured nothing overwrote it during tunnel setup or DHCP refresh.
🎯 Confirmation
After all changes:
curl ifconfig.io
>> 149.102.228.16 # ProtonVPN exit IP!
And:
ping 1.1.1.1
>> Success
At this point, WSL was fully routed through the host, DNS was working, and my tunnel was leak-free.
🔁 Reboot Protection
After reboot, ProtonVPN disabled my internet. The issue? NAT rules don’t persist automatically.
Fix: Recreate NAT rule using PowerShell after reboot:
New-NetNat -Name "WSLNat" -InternalIPInterfaceAddressPrefix 10.254.1.0/24
If desired, this can be scripted or added to a Scheduled Task.
🚫 Rolling Back Cleanly (If Needed)
To undo everything:
- Remove NAT rule:
Remove-NetNat -Name "WSLNat"
- Reset route in WSL:
sudo ip route del default sudo dhclient eth0
- Restore DNS:
sudo chattr -i /etc/resolv.conf sudo rm /etc/resolv.conf echo "nameserver 8.8.8.8" | sudo tee /etc/resolv.conf
⚡ Final Thoughts
This setup gives me WSL with full bridged networking, ProtonVPN privacy, and controlled DNS—all with minimal dependencies. Next steps? Script it all so I never have to touch it after reboot.
Need help configuring your own WSL tunnel flow? Start with ip route
, validate with curl
, and always double-check your NAT rules.