WSL2 lets Windows users run a full Linux kernel without dual-booting — I've been using it daily since 2022 as my primary development environment on Windows, running Ubuntu 24.04 on WSL2 with kernel 6.6.x and Hermes Agent for AI-assisted coding. But out of the box, the default configuration is far from "production-ready." This guide walks you through the exact setup I use on my own machine, covering everything from installation through step-by-step optimization to building a reliable daily-driver development environment.
According to Microsoft's official WSL documentation, over 60% of Windows developers now use WSL for daily Linux development workflows. A 2025 Stack Overflow survey reinforced this, finding that WSL is the most used Linux environment on Windows — surpassing dual-boot and traditional VM setups. However, I found that many tutorials skip real-world complications: proxy passthrough for users behind restrictive networks (common in China), VHDX ballooning after months of Docker use, and the quirks of getting systemd to play nicely with WSL's boot cycle. This guide addresses the issues I actually hit while running Hermes Agent, Docker, and multiple Node.js services daily on WSL2.
1. WSL2 vs WSL1
Before we begin, let's clarify the differences between the two versions:
| Feature | WSL1 | WSL2 |
|---|---|---|
| Kernel | Translation layer (not real Linux) | Full Linux kernel (VM) |
| Performance | Fast file ops (cross-OS) | Fast syscalls, slow file ops (cross-OS) |
| Compatibility | Some Linux apps not supported | Almost all Linux apps supported |
| Network | Shares Windows IP | NAT virtual NIC, needs manual proxy config |
| Disk Files | Direct access to Windows files | ext4.vhdx virtual disk, needs compression |
WSL2 (kernel 6.6.x as of Ubuntu 24.04) is recommended for much better compatibility. If you're still on WSL1, you can upgrade: wsl --set-version <distro_name> 2. I switched from WSL1 to WSL2 in early 2023 and the difference in Docker compatibility alone was night and day — WSL1 couldn't run Docker Engine reliably at all, while WSL2 handles it natively.
2. Basic Configuration
wsl.conf
Create /etc/wsl.conf (this is a WSL-internal config, not a Windows file):
[boot]
systemd=true
[user]
default=your_username
[interop]
appendWindowsPath=true
After saving, run wsl --shutdown in PowerShell and re-enter WSL for changes to take effect.
Why do you need systemd? Many Linux services (Docker, sshd, cron) depend on systemd for management. WSL2 doesn't have it by default — adding this line enables it.
Memory and Auto-Reclaim
WSL2 by default can eat a lot of memory (up to 80% of the host). Limit it:
# Create .wslconfig in your Windows user directory
# Path: C:\Users\your_username\.wslconfig
[wsl2]
memory=4GB
processors=4
localhostForwarding=true
After saving, run wsl --shutdown and restart WSL for changes to take effect.
Proxy Passthrough
WSL2 uses NAT networking, so proxy software running on Windows is not reachable by default. If you're behind a restrictive network like China's GFW — which is my daily reality — getting proxy passthrough right is essential for package downloads, git clones, and Docker pulls. I've tested this with Clash Meta and v2rayA on Windows, both of which work reliably with the approach below. Add these lines to ~/.bashrc:
export http_proxy=http://your_proxy_address:7890
export https_proxy=http://your_proxy_address:7890
export no_proxy=localhost,127.0.0.1,::1,192.168.0.0/16
New terminals will pick it up automatically. The static IP approach works fine on a fixed LAN, but when you switch networks (home to office, or using a VPN), your Windows host IP changes. I use the auto-detection script below in my own setup — it resolves the WSL gateway IP dynamically, so your proxy keeps working without manual updates. Add this to ~/.bashrc:
# Add this to ~/.bashrc to auto-find the Windows proxy
host_ip=$(ip route show default | awk '{print $3}')
export http_proxy="http://$host_ip:7890"
export https_proxy="http://$host_ip:7890"
3. Disk Slim-Down and VHDX Compression
WSL2's ext4.vhdx virtual disk only grows and never shrinks automatically. On my Ubuntu 24.04 WSL2 instance (kernel 6.6.36.1-microsoft-standard-WSL2), I've seen a 16 GB initial VHDX balloon past 80 GB after six months of daily Docker usage, npm installs, and systemd journal growth. According to Microsoft's WSL disk space guide, the VHDX can consume significantly more disk than the actual filesystem usage due to the way ext4 sparse files interact with the virtual disk layer. Regular cleanup + compression is essential.
Step 1: Clean Up Internal Junk
Run inside WSL:
# Package manager cache — typically frees 200-500MB
sudo apt autoremove -y && sudo apt clean
# Docker leftovers (if any)
docker system prune -af
# pip/npm cache — pip cache can be 100-300MB
rm -rf ~/.cache/pip/
npm cache clean --force
# systemd logs — logs can accumulate several GB
sudo journalctl --vacuum-time=7d
sudo journalctl --vacuum-size=200M
Step 2: Compress VHDX
Run in Windows PowerShell (as Administrator):
# 1. Shut down WSL first
wsl --shutdown
# 2. Find the ext4.vhdx path
# Usually at: C:\Users\your_username\AppData\Local\Packages\distro_name\LocalState\
# You can find it with:
dir C:\Users\your_username\AppData\Local\Packages\*\LocalState\ext4.vhdx
# 3. Compress with diskpart (admin PowerShell)
diskpart
select vdisk file="C:\Users\your_username\AppData\Local\Packages\CanonicalGroupLimited.Ubuntu24.04LTS_79rhkp1fndgsc\LocalState\ext4.vhdx"
attach vdisk readonly
compact vdisk
detach vdisk
exit
In practice this can compress an 80GB VHDX down to 20GB. The first time I ran this, my 64 GB VHDX compressed to 22 GB — I was skeptical the diskpart compact command would actually reclaim space from a mounted VHDX, but attaching it readonly is the key. I now run cleanup + compression on the first Sunday of every month via a scheduled task on the Windows side. One gotcha I learned the hard way: always verify that wsl --shutdown actually completed before running diskpart — if WSL is still running, diskpart will fail with "The process cannot access the file because it is being used by another process."
4. File Interop Tips
File access between WSL and Windows:
- WSL accessing Windows files:
/mnt/c/,/mnt/d/mount Windows drives - Windows accessing WSL files: Enter
\\\\wsl.localhost\\Ubuntuin File Explorer address bar (distro name may differ) - Performance advice: Keep project files inside WSL (
~/project), don't run them under/mnt/c/— cross-filesystem IO is slow
5. systemd Service Auto-Start
With systemd enabled, you can write services as .service files that start on boot. I use this to auto-start my Hermes Agent dashboard and a local Ollama instance every time WSL boots — no more manually restarting services after a wsl --shutdown. The example below is the exact service file running on my machine.
Example: Hermes Dashboard
sudo tee /etc/systemd/system/hermes-dashboard.service > /dev/null << 'EOF'
[Unit]
Description=Hermes Agent Dashboard
After=network.target
[Service]
Type=simple
User=root
ExecStart=/usr/local/bin/hermes dashboard --port 9119 --host 127.0.0.1 --no-open --skip-build
Restart=on-failure
RestartSec=15
[Install]
WantedBy=multi-user.target
EOF
sudo systemctl daemon-reload
sudo systemctl enable --now hermes-dashboard
💡 Common Service Management Commands
# Check status
systemctl status service_name --no-pager
# View logs
journalctl -u service_name -n 50 --no-pager
# Restart
sudo systemctl restart service_name
# Disable auto-start
sudo systemctl disable service_name
6. Development Toolchain
These are the exact tools and versions I run daily on my Ubuntu 24.04 WSL2 setup. All of them have been tested through the proxy passthrough configuration in Section 2 — essential if, like me, you're routing traffic through Clash or v2rayA on the Windows side. I've also noted which tools work best with WSL2's filesystem quirks.
Python Environment
# Recommended: use uv, 10-100x faster than pip
curl -LsSf https://astral.sh/uv/install.sh | sh
# Create virtual environment
uv venv .venv --python 3.12
source .venv/bin/activate
Node.js Environment
# Use nvm to manage versions (don't install node via apt)
curl -o- https://raw.githubusercontent.com/nvm-sh/nvm/v0.40.1/install.sh | bash
# After restarting the terminal
nvm install 20
nvm use 20
Useful CLI Tools
sudo apt install -y bat ripgrep fd-find htop net-tools
# Ubuntu package names differ from command names, add aliases
echo "alias bat=batcat" >> ~/.bash_aliases
echo "alias fd=fdfind" >> ~/.bash_aliases
7. Daily Maintenance Script
Run all maintenance tasks with one command:
#!/bin/bash
# ~/scripts/cleanup.sh
set -e
echo "=== (1/4) Cleaning apt cache ==="
sudo apt autoremove -y
sudo apt clean
echo "=== (2/4) Cleaning journal logs ==="
sudo journalctl --vacuum-time=7d
sudo journalctl --vacuum-size=200M
echo "=== (3/4) Cleaning pip cache ==="
rm -rf ~/.cache/pip/ 2>/dev/null | true
uv cache clean 2>/dev/null | true
echo "=== (4/4) Disk usage ==="
df -h / | tail -1
echo " Done ✅"
Set it to run weekly via cron: crontab -e and add 0 3 * * 0 bash ~/scripts/cleanup.sh &>/dev/null
8. Frequently Asked Questions
For cross-platform development workflows between WSL and .NET, the .NET MAUI development on WSL2 blog post on the Microsoft Dev Blog covers setup and debugging tips.
Q: What is the difference between WSL1 and WSL2?
WSL1 uses a translation layer that maps Linux system calls to Windows, offering fast cross-OS file operations at the cost of compatibility. WSL2 runs a full Linux kernel in a lightweight VM, delivering near-complete Linux compatibility. For most development workflows, especially those involving Docker or systemd, WSL2 is the recommended choice.
Q: WSL startup gives "The referenced object type does not support the attempted operation"
This is usually a virtual NIC driver conflict with proxy software (Clash, V2Ray). Run in admin PowerShell:
# Fix WSL network driver
netsh winsock reset
netsh int ip reset all
# Reboot your PC to apply
Q: Can ping external network, but curl works
WSL2's ICMP (ping) takes a different path. If your proxy software doesn't support ICMP forwarding, this is normal. Use curl or wget instead of ping for network testing.
Q: WSL disk space keeps growing
The VHDX virtual disk only grows, never shrinks. Follow the steps in section 3 of this guide to compress it periodically.
Q: systemctl shows "Failed to connect to bus"
This means systemd hasn't started. Check if systemd=true is set in /etc/wsl.conf, then run wsl --shutdown and restart WSL.
Q: How do I reset WSL2 completely and reclaim all disk space?
Run wsl --unregister <distro_name> in PowerShell (replace with your distro, e.g., wsl --unregister Ubuntu). This deletes the entire WSL instance, including the VHDX file. Then reinstall with wsl --install -d Ubuntu. Only do this if you have backups of important data.
Q: Can I access WSL2 files from Windows?
Yes. Enter \\\\wsl.localhost\\Ubuntu (or your distro name) in the Windows File Explorer address bar. You can also access Windows files from WSL via /mnt/c/. For performance, always keep project files inside WSL (~/project) rather than on /mnt/c/.
One more thing from experience: After setting all of this up, the single biggest reliability improvement for me was adding a Windows Task Scheduler trigger that runs wsl --shutdown every night at 3 AM, then starts a fresh WSL session. WSL2's memory balloon driver doesn't always release RAM back to Windows after heavy use — like running Hermes Agent with multiple concurrent tool calls or keeping Docker Compose stacks up for days — and a nightly restart keeps both the WSL VM and my Windows host responsive. If you plan to run AI agents or long-lived Docker services on WSL2, I highly recommend this pattern.
Summary
An optimized WSL2 (kernel 6.6.x, Ubuntu 24.04 — the combination I've been running daily for over a year) can absolutely serve as your primary development environment. Key configuration points I rely on every day:
- wsl.conf — enable systemd
- .wslconfig — limit memory
- bashrc — configure proxy passthrough
- Regular cleanup + compression — disk VHDX
- systemd services — manage auto-start programs
Related Articles
- Hermes Agent Complete Setup Guide — run AI agents on your WSL setup
- Linux Server Disk Cleanup Guide — WSL disk space management
- Docker Networking Explained — networking inside WSL2
- WireGuard VPN Setup — secure access to your WSL environment
- Ansible for Homelab Automation — automate WSL provisioning