Skip to content

Commit c454ae9

Browse files
committed
new post / 2026-03-14-Windows-WSL-DNS-and-VPN.md
1 parent 123948e commit c454ae9

1 file changed

Lines changed: 199 additions & 0 deletions

File tree

Lines changed: 199 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,199 @@
1+
---
2+
authors:
3+
- copdips
4+
categories:
5+
- linux
6+
- network
7+
- ubuntu
8+
comments: true
9+
date:
10+
created: 2026-03-14
11+
updated: 2026-03-14
12+
description: Windows 11 + WSL 2 DNS tunneling with OpenVPN split tunnel.
13+
---
14+
15+
# Windows 11 WSL2 DNS and OpenVPN Split Tunnel
16+
17+
On modern Windows 11 + WSL 2, the reliable VPN-friendly DNS path is WSL DNS tunneling. If you want Linux tools inside WSL to follow the same DNS policy as Windows apps, keep `/etc/resolv.conf` auto-generated and let the Windows DNS Client make the routing and suffix decisions.
18+
19+
This post focuses on the current Windows 11 + WSL 2 model, not the older manual `resolv.conf` workaround. It also shows how to keep OpenVPN in split-tunnel mode while preserving internal DNS resolution in both Windows and WSL.
20+
21+
<!-- more -->
22+
23+
## Modern WSL2 DNS on Windows 11
24+
25+
### Recommended Configuration
26+
27+
In Windows, configure `%UserProfile%\.wslconfig`:
28+
29+
```ini
30+
[wsl2]
31+
# Optional, already the default on current WSL releases
32+
# dnsTunneling=true
33+
```
34+
35+
In WSL, keep `/etc/wsl.conf` simple:
36+
37+
```ini
38+
[network]
39+
# Optional, already the default; keep it enabled for WSL DNS tunneling
40+
# generateResolvConf=true
41+
```
42+
43+
If you also want `systemd`, enable it separately:
44+
45+
```ini
46+
[boot]
47+
systemd=true
48+
```
49+
50+
Then restart WSL from PowerShell:
51+
52+
```powershell
53+
wsl --shutdown
54+
```
55+
56+
Notes:
57+
58+
- `dnsTunneling=true` is the feature that makes WSL DNS follow Windows DNS Client behavior. Microsoft specifically recommends it when you use a VPN, because many VPN clients rely on NRPT rules, and those rules are only applied to WSL DNS queries when DNS tunneling is enabled.
59+
- What matters for DNS tunneling is that you do not disable `generateResolvConf`, because Microsoft notes DNS tunneling will not be successfully enabled if `generateResolvConf=false`.
60+
- `systemd=true` is optional. It is useful for services and timers, but it does not need to "own" `/etc/resolv.conf` in this setup.
61+
62+
### What `/etc/resolv.conf` Should Look Like
63+
64+
With DNS tunneling enabled, WSL generates `resolv.conf` and points it at the Windows-side DNS tunnel IP:
65+
66+
```bash
67+
$ cat /etc/resolv.conf
68+
# This file was automatically generated by WSL.
69+
nameserver 10.255.255.254
70+
search home.lan corp.example
71+
```
72+
73+
Notes:
74+
75+
- `10.255.255.254` is WSL's `dnsTunnelingIpAddress`.
76+
- In NAT mode with DNS tunneling enabled, WSL brings over Windows DNS suffixes into the `search` line. The order follows Windows DNS behavior: global suffixes first, then supplemental suffixes, then per-interface suffixes.
77+
- The exact `search` values change when your network or VPN state changes.
78+
79+
### The Resolution Path
80+
81+
When a WSL app resolves `app.corp.example`, the flow is:
82+
83+
1. The Linux app reads `/etc/resolv.conf` and sends the query to `10.255.255.254`.
84+
2. WSL tunnels the request directly to Windows instead of sending a normal DNS packet from the VM to the host.
85+
3. The Windows DNS Client applies Windows DNS policy: NRPT rules, DNS suffix search order, per-interface DNS servers, and Windows-side DoH or DoT settings.
86+
4. Windows forwards the query to the appropriate resolver, such as your home router or the VPN's internal DNS servers.
87+
88+
This is the key change on modern WSL 2: Windows, not a hand-configured Linux stub resolver, makes the final DNS policy decision.
89+
90+
### Manual `resolv.conf` Mode (`generateResolvConf=false`)
91+
92+
You can still disable WSL's generated `resolv.conf` and point Linux at `systemd-resolved` or another local resolver, but for modern Windows 11 + WSL 2 + VPN setups that is an advanced custom path, not the recommended one.
93+
94+
If you set `generateResolvConf=false`:
95+
96+
- you opt out of the WSL-generated DNS tunnel configuration;
97+
- you become responsible for upstream DNS servers and suffix search behavior inside Linux;
98+
- WSL will no longer automatically mirror Windows VPN DNS behavior for you.
99+
100+
So if your main goal is "WSL should behave like Windows when the VPN connects," keep `generateResolvConf=true`.
101+
102+
## OpenVPN Split Tunnel with DNS
103+
104+
A split tunnel means only company routes go through the VPN. Your normal internet traffic keeps using the local connection, while internal company names still resolve correctly.
105+
106+
### OpenVPN Client Configuration
107+
108+
Use a client config like this:
109+
110+
```ovpn
111+
# Prevent the VPN from replacing your normal internet route
112+
route-nopull
113+
114+
# Send only company networks through the VPN
115+
route 10.0.0.0 255.0.0.0 vpn_gateway
116+
route 172.16.0.0 255.240.0.0 vpn_gateway
117+
118+
# Use company DNS on the VPN adapter
119+
dhcp-option DNS 10.0.0.1
120+
dhcp-option DNS 10.0.0.2
121+
122+
# Set the VPN adapter's connection-specific DNS suffix
123+
dhcp-option DOMAIN corp.example
124+
125+
# Optional: if your company uses more than one internal suffix
126+
# dhcp-option DOMAIN-SEARCH eng.corp.example
127+
# dhcp-option DOMAIN-SEARCH corp.example
128+
```
129+
130+
The key line here is `route-nopull`. Without it, many company VPN profiles push a full-tunnel default route, often via `redirect-gateway`, which sends all traffic through the VPN gateway instead of only company traffic.
131+
132+
That usually makes normal internet access slower and more fragile. Public traffic such as Microsoft Teams calls, public Docker image pulls, package downloads, and ordinary web browsing can all end up going through the corporate VPN path even though they do not need to.
133+
134+
With `route-nopull`, you keep the VPN tunnel itself, but you only add the private routes you actually want to send through it.
135+
136+
!!! note "Manual routes required"
137+
138+
The tradeoff is that you need to know the company private subnets in advance and add them manually. If you miss one, that internal network will stay on your normal local route and will not be reachable through the VPN.
139+
140+
### Why `dhcp-option DOMAIN` Matters
141+
142+
`dhcp-option DOMAIN corp.example` does not create Windows NRPT rules by itself. What it does is set the VPN adapter's connection-specific DNS suffix.
143+
144+
That matters for two reasons:
145+
146+
- short names like `app` can expand to `app.corp.example`;
147+
- with WSL DNS tunneling enabled, Windows DNS suffixes are propagated into WSL's `search` line, so Linux tools benefit from the same suffix.
148+
149+
If your VPN already deploys NRPT rules, Windows will still use those rules for `*.corp.example`. The `DOMAIN` option complements NRPT by making suffix search consistent instead of leaving Windows and WSL to guess.
150+
151+
This is also why `.local` is a poor example for corporate DNS. `.local` is typically treated as mDNS, not normal unicast DNS, so it can make a healthy VPN setup look broken.
152+
153+
### How to Find Your VPN DNS Servers
154+
155+
To get the correct internal DNS IPs:
156+
157+
1. Connect to the VPN using the original working profile.
158+
2. In PowerShell, run `ipconfig /all`.
159+
3. Find the OpenVPN adapter.
160+
4. Copy the IPs listed under `DNS Servers`.
161+
5. Reuse those IPs in your split-tunnel config.
162+
163+
### OpenVPN 2.7+ and `pull-filter`
164+
165+
`route-nopull` tells the client not to install server-pushed routes and DHCP-style DNS options. That is what prevents the VPN from silently turning your split tunnel back into a full tunnel. In OpenVPN 2.7+, you may still see warnings because the server did push those directives and your client is overriding them.
166+
167+
`pull-filter ignore` is the cleanup step: it drops matching server-pushed directives before OpenVPN processes them. That keeps the logs quieter and makes it explicit that your local client config is authoritative.
168+
169+
```ovpn
170+
pull-filter ignore "redirect-gateway"
171+
pull-filter ignore "route"
172+
pull-filter ignore "dhcp-option "
173+
```
174+
175+
Notes:
176+
177+
- `pull-filter` uses prefix matching.
178+
- `pull-filter ignore "route"` drops pushed `route`, `route-gateway`, and other route-related directives.
179+
- `pull-filter ignore "dhcp-option "` drops pushed DNS and domain suffix options so they do not conflict with the values you set locally.
180+
- Only add these filters if the server really is pushing overlapping directives and you want the local client config to win.
181+
182+
## Verification
183+
184+
Inside WSL, confirm that DNS tunneling is active:
185+
186+
```bash
187+
grep -E '^(nameserver|search)' /etc/resolv.conf
188+
# nameserver 10.255.255.254
189+
# search home.lan corp.example
190+
```
191+
192+
Then test name resolution and routing:
193+
194+
- `getent hosts app.corp.example`: confirms that a fully qualified internal name resolves.
195+
- `getent hosts app`: if you rely on short names, this confirms that the DNS suffix search list is working.
196+
- `nc -zv app.corp.example 443`: confirms both DNS resolution and reachability over the VPN, if the target app is actually listening on TCP port 443.
197+
- `curl ifconfig.me`: should still show your normal local public IP, proving that internet traffic is not being forced through the VPN.
198+
199+
If `/etc/resolv.conf` points at `127.0.0.53` or a manually configured public DNS server instead of `10.255.255.254`, you are not using the modern WSL DNS tunneling path described above.

0 commit comments

Comments
 (0)