A comprehensive guide to understanding WSL's architecture, networking, file sharing, terminal usage, and VS Code integration.
- WSL Architecture Overview
- Networking Between Host and Linux
- File Sharing Between Windows and Linux
- Effective Terminal Usage
- VS Code Remote Architecture
WSL has two versions with fundamentally different architectures:
┌─────────────────────────────────────────────┐
│ Windows NT Kernel │
├─────────────────────────────────────────────┤
│ Linux System Call Translation Layer │
│ (lxss.sys / lxcore.sys) │
├─────────────────────────────────────────────┤
│ Linux User Space │
│ (Ubuntu, Debian, etc. distributions) │
└─────────────────────────────────────────────┘
- Translation Layer: Linux system calls are translated to Windows NT kernel calls in real-time
- No real Linux kernel: Uses a compatibility layer
- Pros: Fast file system access to Windows files
- Cons: Incomplete syscall support, slower Linux operations
┌─────────────────────────────────────────────────────────┐
│ Windows Host │
├─────────────────────────────────────────────────────────┤
│ Hyper-V Hypervisor │
├────────────────────────┬────────────────────────────────┤
│ Windows NT Kernel │ Lightweight Utility VM │
│ │ ┌──────────────────────────┐ │
│ │ │ Real Linux Kernel │ │
│ │ ├──────────────────────────┤ │
│ │ │ Linux User Space │ │
│ │ │ (ext4 filesystem) │ │
│ │ └──────────────────────────┘ │
└────────────────────────┴────────────────────────────────┘
- Real Linux Kernel: Runs an actual Linux kernel in a lightweight VM
- Hyper-V: Uses virtualization (but highly optimized)
- Pros: Full syscall compatibility, faster Linux file operations
- Cons: Slower cross-filesystem access
| Component | Description |
|---|---|
wsl.exe |
Main CLI tool to manage WSL |
wslhost.exe |
Handles communication between Windows and WSL |
init |
WSL's init system (manages services in the VM) |
9P Protocol Server |
Enables file sharing between Windows and Linux |
WSL 2 runs in a VM with its own virtual network adapter, creating a NAT (Network Address Translation) setup:
┌─────────────────────────────────────────────────────────────┐
│ Physical Network │
│ (Your Router/Internet) │
└───────────────────────────┬─────────────────────────────────┘
│
┌───────────────────────────▼─────────────────────────────────┐
│ Windows Host │
│ IP: 192.168.1.x (from your router) │
│ ┌─────────────────────────────────────────────────────┐ │
│ │ Virtual NAT Network │ │
│ │ (vEthernet WSL) │ │
│ │ Subnet: 172.x.x.x │ │
│ │ ┌───────────────────────────────────────────────┐ │ │
│ │ │ WSL 2 VM │ │ │
│ │ │ IP: 172.x.x.x (dynamic) │ │ │
│ │ │ │ │ │
│ │ │ eth0 ◄──── Virtual Network Adapter │ │ │
│ │ └───────────────────────────────────────────────┘ │ │
│ └─────────────────────────────────────────────────────┘ │
└─────────────────────────────────────────────────────────────┘
# Get WSL's IP address (from inside WSL)
ip addr show eth0 | grep inet
# Get Windows host IP (from inside WSL)
cat /etc/resolv.conf | grep nameserver
# The nameserver IP is your Windows host IP# WSL services on localhost are automatically forwarded
# A server running on WSL port 3000 is accessible at:
# http://localhost:3000 (from Windows browser)# Get the Windows host IP
WIN_HOST=$(cat /etc/resolv.conf | grep nameserver | awk '{print $2}')
# Access Windows service (e.g., SQL Server on port 1433)
curl http://$WIN_HOST:1433# Port forwarding required (run in PowerShell as Admin)
netsh interface portproxy add v4tov4 listenport=3000 listenaddress=0.0.0.0 connectport=3000 connectaddress=$(wsl hostname -I)Enable in %USERPROFILE%\.wslconfig:
[wsl2]
networkingMode=mirroredWith mirrored mode:
- WSL shares the same IP as Windows
- No NAT translation needed
- Localhost works seamlessly in both directions
- IPv6 support included
┌─────────────────────────────────────────────────────────────┐
│ Windows │
│ ┌─────────────────────────────────────────────────────┐ │
│ │ 9P Protocol Server │ │
│ │ (Running in Windows) │ │
│ │ Exposes: C:\, D:\, etc. as /mnt/c, /mnt/d │ │
│ └──────────────────────────┬──────────────────────────┘ │
│ │ 9P Protocol │
│ ┌──────────────────────────▼──────────────────────────┐ │
│ │ WSL 2 VM │ │
│ │ ┌────────────────────────────────────────────────┐ │ │
│ │ │ 9P Client (in kernel) │ │ │
│ │ │ Mounts Windows drives at /mnt/* │ │ │
│ │ └────────────────────────────────────────────────┘ │ │
│ │ ┌────────────────────────────────────────────────┐ │ │
│ │ │ Native ext4 Filesystem │ │ │
│ │ │ (Linux home, /usr, etc.) │ │ │
│ │ └────────────────────────────────────────────────┘ │ │
│ └─────────────────────────────────────────────────────┘ │
└─────────────────────────────────────────────────────────────┘
| Location | Windows Path | Linux Path |
|---|---|---|
| Windows C: drive | C:\Users\you |
/mnt/c/Users/you |
| Windows D: drive | D:\Projects |
/mnt/d/Projects |
| WSL Linux home | \\wsl$\Ubuntu\home\you |
~ or /home/you |
| WSL root | \\wsl$\Ubuntu\ |
/ |
Performance Comparison (relative speeds):
Linux files from Linux: ████████████████████ 100%
Windows files from Windows: ████████████████████ 100%
Linux files from Windows: ████████████░░░░░░░░ 60%
Windows files from Linux: ████████░░░░░░░░░░░░ 40% ← Slowest!
Best Practices:
- Store project files in the Linux filesystem (
~/projects/) - Clone git repos inside WSL, not in
/mnt/c/ - Use Windows filesystem only for files that need Windows apps
Configure in /etc/wsl.conf:
[automount]
enabled = true
root = /mnt/
options = "metadata,umask=22,fmask=11"
mountFsTab = true
[interop]
enabled = true
appendWindowsPath = true# List installed distributions
wsl --list --verbose
wsl -l -v
# Set default distribution
wsl --set-default Ubuntu
# Start specific distribution
wsl -d Ubuntu
# Run a single command
wsl ls -la /home
# Shutdown all WSL instances
wsl --shutdown
# Terminate specific distribution
wsl --terminate Ubuntu
# Export/Import distributions
wsl --export Ubuntu ubuntu-backup.tar
wsl --import Ubuntu-Copy C:\WSL\Ubuntu-Copy ubuntu-backup.tar
# Update WSL
wsl --update
# Check WSL version
wsl --versionWindows Terminal automatically detects WSL distributions. Configure in settings.json:
{
"profiles": {
"list": [
{
"name": "Ubuntu",
"source": "Windows.Terminal.Wsl",
"startingDirectory": "//wsl$/Ubuntu/home/username",
"colorScheme": "One Half Dark",
"fontFace": "CaskaydiaCove Nerd Font"
}
]
}
}# Run Windows commands from Linux
explorer.exe . # Open current folder in Explorer
notepad.exe myfile.txt # Open file in Notepad
cmd.exe /c dir # Run CMD command
powershell.exe Get-Process # Run PowerShell command
# Pipe between Windows and Linux
cat /etc/passwd | clip.exe # Copy to Windows clipboard
powershell.exe Get-Date | grep 2024 # Pipe Windows output to Linux
# Open files with default Windows app
wslview document.pdf # Requires wslu package~/.bashrc or ~/.zshrc:
# Useful aliases
alias explorer='explorer.exe .'
alias clip='clip.exe'
alias open='wslview'
# Access Windows environment variables
export WIN_HOME=$(wslpath "$(cmd.exe /c 'echo %USERPROFILE%' 2>/dev/null | tr -d '\r')")
# Add Windows paths selectively (instead of all)
export PATH="$PATH:/mnt/c/Program Files/Microsoft VS Code/bin"Share Windows SSH agent with WSL using npiperelay:
# In ~/.bashrc
export SSH_AUTH_SOCK=$HOME/.ssh/agent.sock
ss -a | grep -q $SSH_AUTH_SOCK
if [ $? -ne 0 ]; then
rm -f $SSH_AUTH_SOCK
setsid socat UNIX-LISTEN:$SSH_AUTH_SOCK,fork EXEC:"npiperelay.exe -ei -s //./pipe/openssh-ssh-agent",nofork &
fiVS Code uses a client-server architecture for WSL development:
┌─────────────────────────────────────────────────────────────────────────┐
│ Windows Host │
│ ┌───────────────────────────────────────────────────────────────────┐ │
│ │ VS Code Desktop (Client) │ │
│ │ ┌─────────────────┐ ┌─────────────────┐ ┌──────────────────┐ │ │
│ │ │ UI Renderer │ │ Extension Host │ │ Terminal Client │ │ │
│ │ │ (Electron) │ │ (Windows) │ │ │ │ │
│ │ └────────┬────────┘ └────────┬────────┘ └────────┬─────────┘ │ │
│ │ │ │ │ │ │
│ └───────────┼────────────────────┼────────────────────┼─────────────┘ │
│ │ WebSocket / stdin/stdout │ │
│ │ Communication Channel │ │
│ ┌───────────▼────────────────────▼────────────────────▼─────────────┐ │
│ │ WSL 2 VM │ │
│ │ ┌─────────────────────────────────────────────────────────────┐ │ │
│ │ │ VS Code Server │ │ │
│ │ │ (~/.vscode-server/bin/<commit-id>/) │ │ │
│ │ │ ┌─────────────────┐ ┌─────────────────┐ ┌─────────────┐ │ │ │
│ │ │ │ Extension Host │ │ File Watcher │ │ Language │ │ │ │
│ │ │ │ (Linux exts) │ │ (Linux FS) │ │ Servers │ │ │ │
│ │ │ └─────────────────┘ └─────────────────┘ └─────────────┘ │ │ │
│ │ │ ┌─────────────────┐ ┌─────────────────┐ ┌─────────────┐ │ │ │
│ │ │ │ Terminal │ │ Debugger │ │ Git │ │ │ │
│ │ │ │ (bash/zsh) │ │ (gdb/lldb) │ │ (native) │ │ │ │
│ │ │ └─────────────────┘ └─────────────────┘ └─────────────┘ │ │ │
│ │ └─────────────────────────────────────────────────────────────┘ │ │
│ │ │ │
│ │ Project Files: /home/user/projects/myapp │ │
│ └────────────────────────────────────────────────────────────────────┘ │
└─────────────────────────────────────────────────────────────────────────┘
- UI Renderer: Electron-based GUI running on Windows
- Local Extension Host: Runs UI-only extensions (themes, keymaps)
- Communication Layer: WebSocket connection to VS Code Server
- Location:
~/.vscode-server/bin/<version>/ - Remote Extension Host: Runs workspace extensions (Python, ESLint, etc.)
- File System Access: Direct ext4 access (fast!)
- Process Management: Debuggers, terminals, tasks run natively
Extensions are split based on where they need to run:
┌─────────────────────────────────────────────────────────────┐
│ Extension Types │
├─────────────────────────────┬───────────────────────────────┤
│ UI Extensions │ Workspace Extensions │
│ (Run on Windows) │ (Run in WSL) │
├─────────────────────────────┼───────────────────────────────┤
│ • Themes │ • Language Servers │
│ • Icon packs │ • Linters (ESLint, Pylint) │
│ • Keymaps │ • Formatters (Prettier) │
│ • UI customizations │ • Debuggers │
│ │ • Git extensions │
│ │ • Build tools │
└─────────────────────────────┴───────────────────────────────┘
# From Windows Terminal/PowerShell
code --remote wsl+Ubuntu /home/user/project
# From inside WSL terminal
cd ~/project
code .
# Opening specific file
code --remote wsl+Ubuntu /home/user/project/main.pyUser settings.json:
{
"remote.WSL.fileWatcher.polling": false,
"remote.WSL.debug": false,
"terminal.integrated.defaultProfile.linux": "bash",
"terminal.integrated.profiles.linux": {
"bash": {
"path": "/bin/bash",
"icon": "terminal-bash"
},
"zsh": {
"path": "/usr/bin/zsh"
}
},
"files.watcherExclude": {
"**/node_modules/**": true,
"**/.git/objects/**": true
}
}-
Store projects in Linux filesystem
# Good ✓ ~/projects/myapp # Bad ✗ (slow!) /mnt/c/Users/you/projects/myapp
-
Exclude heavy folders from file watching
{ "files.watcherExclude": { "**/node_modules/**": true, "**/vendor/**": true, "**/.git/objects/**": true, "**/dist/**": true } } -
Install extensions in WSL
- Click "Install in WSL" when prompted
- Check installed location: Extensions sidebar shows "WSL: Ubuntu" tag
┌──────────────────────────────────────────────────────────────┐
│ VS Code Client │
│ ┌──────────────────────────────────────────────────────┐ │
│ │ Debug Adapter Protocol (DAP) │ │
│ │ Client │ │
│ └────────────────────────┬─────────────────────────────┘ │
│ │ JSON-RPC over WebSocket │
├───────────────────────────┼──────────────────────────────────┤
│ WSL 2 VM │
│ ┌────────────────────────▼─────────────────────────────┐ │
│ │ Debug Adapter │ │
│ │ (e.g., debugpy, node-debug2) │ │
│ └────────────────────────┬─────────────────────────────┘ │
│ │ │
│ ┌────────────────────────▼─────────────────────────────┐ │
│ │ Target Application │ │
│ │ (Python script, Node.js app, etc.) │ │
│ └──────────────────────────────────────────────────────┘ │
└──────────────────────────────────────────────────────────────┘
launch.json example:
{
"version": "0.2.0",
"configurations": [
{
"name": "Python: Current File",
"type": "debugpy",
"request": "launch",
"program": "${file}",
"console": "integratedTerminal"
}
]
}| Task | Command |
|---|---|
| Enter WSL | wsl |
| Enter specific distro | wsl -d Ubuntu |
| Run single command | wsl ls -la |
| Open folder in VS Code | code . (from WSL) |
| Shutdown WSL | wsl --shutdown |
| Check WSL status | wsl -l -v |
| Access Windows files | cd /mnt/c/Users/ |
| Access WSL files from Windows | \\wsl$\Ubuntu\home\ |
| Open Explorer here | explorer.exe . |
| Copy to clipboard | `cat file |
# Reset WSL networking
wsl --shutdown
# Then restart WSL
# Check WSL version
wsl --version
# Verify WSL 2 is being used
wsl -l -v
# Should show VERSION 2
# View WSL logs
dmesg | tail -50
# Check mounted drives
mount | grep drvfs