WSL2 tuning — memory, systemd, DNS, I/O in one pass
The seven things to fix right after installing WSL2 — .wslconfig, systemd, DNS, disk reclaim, VS Code integration, mirrored networking.
If you've installed WSL2 via Windows initial setup, the next step is tuning. Running on defaults leads to runaway memory, broken DNS after reboot, ballooning disk, and missing systemd. This guide covers seven tuning steps in one pass — apply once, benefit daily.
Target: Windows 11 (22H2+) + WSL2 + Ubuntu (or any systemd-based distro).
TL;DR
| Tuning | File | Effect |
|---|---|---|
1. .wslconfig | %USERPROFILE%\.wslconfig (Windows) | RAM/CPU/swap caps + GUI · mirrored networking |
2. wsl.conf systemd | /etc/wsl.conf (inside WSL) | Enables systemd → snap · docker · systemctl all work |
| 3. DNS stability | /etc/wsl.conf + /etc/resolv.conf | Prevents DNS drops after VPN / reboot |
| 4. I/O performance | Workspace location | Use WSL-native (/home/...) instead of /mnt/c/... |
| 5. Disk reclaim | export/import | Shrinks bloated vhdx (tens of GB recoverable) |
| 6. VS Code Remote-WSL | One extension | Edit WSL files at native speed |
| 7. Mirrored networking | .wslconfig networkingMode=mirrored | VPN/corp-friendly (Win11 22H2+) |
Prerequisites
- Windows 11 22H2 or newer (some features prefer 23H2+)
- WSL2 installed + at least one systemd-capable distro (Ubuntu, etc.)
- Not installed: in admin PowerShell,
wsl --install
- Not installed: in admin PowerShell,
- Admin rights recommended for
wsl --shutdown(.wslconfigitself is in the user profile)
1. .wslconfig — RAM/CPU/swap caps
By default WSL2 can grab up to ~50% of Windows RAM — a large Node build can push Windows itself into swap. Set explicit caps.
1.1 Template
.wslconfig# PowerShell
Invoke-WebRequest -Uri https://devalice.jaceclub.com/assets/windows/wsl-tuning/wslconfig-template.txt -OutFile $env:USERPROFILE\.wslconfig
Get-FileHash $env:USERPROFILE\.wslconfig -Algorithm SHA256
# expected: BFBDAF7AE486916D8AA4E792F9845416E1B6B6EA535F84E1BBCCA2BE9ACCB3C4
# (lowercase: bfbdaf7ae486916d8aa4e792f9845416e1b6b6ea535f84e1bbcca2be9accb3c4)1.2 Key settings
# %USERPROFILE%\.wslconfig
[wsl2]
memory=8GB # 50–75% of host RAM
swap=4GB # disk swap (0 = disabled)
localhostForwarding=true
guiApplications=true # Linux GUI apps (Win11 default)
# processors=8 # explicit core cap (optional)1.3 Apply
wsl --shutdown # stop all WSL instances
wsl # next start picks up .wslconfig1.4 Verify
Inside WSL:
free -h # memory cap matches (e.g. 8GB)
nproc # CPU count
swapon --show # swap activeA 16GB host machine works well with
memory=10GB. A 32GB machine:memory=16GB.
2. Enable systemd — /etc/wsl.conf
WSL2's default init is not systemd. Modern packages (docker, snap, postgresql service, etc.) expect it.
2.1 Enable
# inside WSL (sudo required)
sudo nano /etc/wsl.confContents:
[boot]
systemd=true
[user]
default=me # default user (optional)Save, then:
# Windows PowerShell
wsl --shutdown
wsl2.2 Verify
ps -p 1 # PID 1 == systemd → success
systemctl status # systemd info shown → OKNow sudo systemctl start docker and friends work properly.
Boot time grows by 1–3 seconds; in exchange you get a real service manager, journal logging, and tab completion.
3. DNS stability
WSL2's default DNS goes through a Windows NAT bridge that often breaks after VPN connect/disconnect or reboot. Symptom: curl github.com works but apt update doesn't, or vice versa.
3.1 Option A — disable auto-DNS + static resolvers
sudo nano /etc/wsl.confAdd:
[network]
generateResolvConf=falseSave → wsl --shutdown → restart.
Now WSL stops rewriting /etc/resolv.conf. Set it manually:
sudo nano /etc/resolv.confnameserver 1.1.1.1
nameserver 8.8.8.8
On corp networks/VPN, add the internal DNS your IT provides.
3.2 Option B — mirrored networking (Win11 22H2+, recommended)
Section 7 makes WSL share Windows' DNS automatically. Most stable on corporate VPN.
4. I/O performance — where to put your work
The most commonly missed tuning. Performance differs sharply:
| Location | Path | Build speed (e.g. npm install) |
|---|---|---|
| WSL native | /home/me/project | ✅ Fast (Linux ext4) |
| Windows mount | /mnt/c/Users/me/project | ❌ 5–10× slower (9p protocol) |
Rule: WSL work lives inside the WSL disk. If Windows needs the same files, use VS Code Remote-WSL (§6) or Syncthing (see file sync) to keep copies on both sides.
4.1 Good pattern
# inside WSL
mkdir -p ~/work
cd ~/work
git clone git@github.com:org/repo.git
cd repo
npm install # fast4.2 Anti-pattern
# clone on Windows, build via WSL
cd /mnt/c/Users/me/Documents/project # cross-mount
npm install # slow (tens of minutes)4.3 When cross-mount is needed
- A Windows-only tool must open the same folder (Photoshop, etc. — rare)
- Editing from Windows IDE — solvable with VS Code Remote-WSL
5. Disk size — vhdx compaction
WSL's .vhdx virtual disk never shrinks automatically. Build a 30GB cache, delete it — the file stays at 30GB.
5.1 Check current size
# PowerShell
Get-ChildItem -Path "$env:LOCALAPPDATA\Packages" -Recurse -Filter "ext4.vhdx" | ForEach-Object {
"{0,-60} {1:N2} GB" -f $_.Directory.Name, ($_.Length / 1GB)
}5.2 Option A — Sparse VHD (Win11 22H2+)
In .wslconfig (already commented out in the §1.1 template):
[experimental]
sparseVhd=truewsl --shutdown enables it. Unused space is reclaimed incrementally.
5.3 Option B — manual compaction (diskpart)
While WSL is shut down:
wsl --shutdown
diskpart
# diskpart>
select vdisk file="C:\Users\me\AppData\Local\Packages\CanonicalGroupLimited.Ubuntu_*\LocalState\ext4.vhdx"
attach vdisk readonly
compact vdisk
detach vdisk
exitTens of GB recoverable. Slow — run overnight.
5.4 Option C — Export/Import (cleanest)
Full backup + recreate. The new vhdx starts at optimal size.
wsl --shutdown
wsl --export Ubuntu C:\backup\ubuntu.tar
wsl --unregister Ubuntu
wsl --import Ubuntu C:\WSL\Ubuntu C:\backup\ubuntu.tarOption C is the most effective but the instance ID / install metadata are recreated. Re-apply systemd config, default user, etc. Best done during a planned migration.
6. VS Code Remote-WSL
Edit WSL files from Windows VS Code at native speed. The standard answer to the cross-mount problem.
6.1 Install
In Windows VS Code marketplace:
- Remote - WSL (
ms-vscode-remote.remote-wsl)
Or from the command line:
code --install-extension ms-vscode-remote.remote-wsl6.2 Use
Inside WSL:
cd ~/work/repo
code .→ Windows VS Code opens, bottom-left shows WSL: Ubuntu. Filesystem, terminal, and extensions all run inside WSL.
Alternatively, in Windows VS Code: Command Palette → WSL: Connect to WSL → pick a folder.
6.3 Extensions to install on the WSL side
On first connect, some extensions ask "Install on WSL?". Recommended yeses:
- ESLint / Prettier
- Python / Pylance
- Go / Rust-Analyzer
- Docker
7. Mirrored networking (Win11 22H2+)
A more elegant fix than §3. WSL mirrors Windows' network interface directly — VPN, corp network, DNS, and localhost behave identically to the host.
7.1 Enable
In .wslconfig:
[wsl2]
networkingMode=mirrored
[experimental]
dnsTunneling=true
autoProxy=truewsl --shutdown and restart.
7.2 Effects
- VPN — WSL automatically goes through the VPN
- Corporate proxy — Windows' IE/Edge proxy is picked up automatically
- localhost — Windows ↔ WSL is bidirectional (no
localhostForwardingneeded) - DNS — same as Windows, most stable
7.3 Caveats
- Conflicts with some Docker Desktop builds — disable temporarily if you hit issues
- Some advanced container networking scenarios behave differently — verify if you do deep container work
Verification
The five checks:
- Inside WSL,
free -hshows the cap from.wslconfig(e.g. 8.0Gi) ps -p 1showssystemdcurl -sS https://www.google.com -o /dev/null && echo OK→ OK (DNS/network)- Both
cd ~ && touch test.txt && lsandcd /mnt/c/Users/$USER && touch test.txt && lswork (only the speed differs) - From VS Code,
code .showsWSL: Ubuntuin the bottom-left
Troubleshooting
.wslconfig changes don't apply
- Forgot
wsl --shutdown. All WSL instances must fully stop before the next start picks up the file. - Location must be
%USERPROFILE%\.wslconfig(your user home), not%LOCALAPPDATA%. - Filename must be
.wslconfig(leading dot, no extension).
Boot fails after enabling systemd
- Common cause: a syntax mistake in
/etc/wsl.conf(e.g. missing[boot]header). - Recovery: from PowerShell,
wsl -u root -d Ubuntuto enter as root and fix/etc/wsl.conf.
apt update returns DNS errors
- Apply §3.1 (manual
/etc/resolv.conf), or switch to §7 mirrored networking. - On VPN, ensure the corporate DNS is added.
npm install is unbearably slow
- §4 — you're working from
/mnt/c/.... Move to~/work.
VS Code Remote-WSL fails to connect
codenot on PATH. Open VS Code on Windows once → Command Palette →Shell Command: Install 'code' command in PATH.- Verify with
code -vinside WSL.
Docker Desktop breaks after mirrored networking
- Docker Desktop was assuming NAT mode. Reconfigure its WSL integration, or disable mirrored mode while using Docker.
vhdx doesn't shrink (§5)
diskpart'scompact vdiskis limited by fragmentation. Option C (export/import) is cleanest.
References
- Windows initial setup — install WSL2 first
- Microsoft WSL — Configuration
- WSL Mirrored networking announcement
- Sparse VHD announcement
Changelog
- 2026-05-12 — Initial English translation (devAlice M2 i18n seed)