Last Update: 10/23/2024
Ever wondered how to seamlessly blend Windows and Linux in your daily workflow?
My friends and colleagues frequently ask about my WSL setup - both for personal projects and professional work.
I used to direct them to an old blog post of mine, but that always required a massive wall of explanatory text, since things have evolved significantly.
So here is my personal "Ultimate WSL2 Setup"
TL;DR
for everyone that doesn't feel like reading my gibberish:
- Win 11 (wslg pre-setup)
- Windows Terminal
- usbipd-win (usb passthrough)
- ArchWSL
- zsh (with some plugins)
- gsudo (sudo for windows)
- wsl-hello-sudo (using windows hello/fingerpint with wsl-sudo)
- wsl-open (open any file/link with native windows executable)
- my dotfiles
- Custom Kernel for car-hacking stuff
Setup
Terminal: Your Gateway to Command Line Bliss
Before diving into WSL and shell configurations, let's get you set up with a proper terminal emulator. The landscape has evolved significantly, and your options are much better than they were a few years ago.
The Windows Terminal has matured into a fantastic choice with an impressive feature set. The best part? It's blazing fast! They've even added a sweet quake-mode feature recently, making it a worthy replacement for the old "conhost.exe".
While Windows Terminal has become my daily driver, it does have a few limitations. If you need advanced features like auto-start in hidden-quake mode or separate always-on-top settings for quake-mode and normal-mode instances, ConEmu remains the most feature-rich alternative - just be prepared for slightly slower performance.
Fonts
Next up, let's talk typography. You'll want fonts with extensive glyph support (icons) - I recommend checking out nerd-fonts. While Windows lacks an official all-in-one installer, you can either use your preferred Windows package manager or cherry-pick specific fonts as I did
Windows Sudo: Trust Me, You'll Want This!
Here's a game-changer: gsudo, essentially bringing sudo to Windows.
On Windows 11, it's as simple as running winget install gsudo
in an elevated PowerShell.
Once installed, you can elevate any Windows process/command with a simple gsudo
prefix.
WSL
I've fallen in love with Arch Linux's minimalist approach, which fits perfectly within WSL's ecosystem. While Arch isn't officially supported, several excellent distro launchers make it possible. I've had great success with ArchWSL, which has proven reliable even in professional settings.
For a basic installation, you can refer to their excellent guide here
If you've never used WSL before or start with a fresh Windows install, use Microsoft's guide to install WSL, but install ArchWSL from their GitHub page, instead of any other distro from the Microsoft store.
Systemd
Recent WSL2 versions finally support Systemd, enabling things like docker without the pesky "Docker for Windows"-App.
Although it's not enabled by default...
To activate it, add this to /etc/wsl.conf
:
[boot]
systemd=true
File system gotchas
While recent Windows versions provide built-in access to Linux files, some compatibility quirks remain. I prefer mapping WSL files as a network drive using \\wsl.localhost\
- simple and effective.
From the Linux side, you can project file permissions and metadata to NTFS, though it requires configuration.
This enables neat tricks like symlinking your Windows-generated SSH folder, eliminating redundant key and config management.
Here's my battle-tested /etc/wsl.conf
configuration:
# Includes enabling Systemd from above
[boot]
systemd=true
# Enable extra metadata options by default
[automount]
enabled = true
root = /mnt/
options = "metadata,rw,umask=22,fmask=11"
mountFsTab = false
# Enable DNS even though these are turned on by default, we’ll specify here just to be explicit.
[network]
generateHosts = true
generateResolvConf = true
[interop]
enabled=true
appendWindowsPath=true
USB Support: Connecting the Physical World
Another feature that is missing from WSL out of the box is support for USB devices.
However, recently (at time of writing) M$ did put some work into it, and posted about a way to make it happen.
That's great news for anyone who's into Arduino or similar stuff or even car-hacking, as I personally find that that kinda stuff is just easier to set up on Linux than on Windows.
Basically, just install usbipd-win...
winget install --interactive --exact dorssel.usbipd-win
For Arch users, that's all you need!
From any elevated command prompt, you can manage USB devices with usbipd wsl list
and usbipd wsl attach --busid XX
.
With gsudo, you can run these commands directly from WSL:
cmd.exe /c gsudo usbipd wsl list
cmd.exe /c gsudo usbipd wsl attach --busid 4-4
WSL-Open: Seamless integration
Want to make your WSL experience even smoother?
wsl-open is a must-have tool. It lets you use Linux's standard xdg-open
command to open files and links with native Windows applications. Installation is a breeze via npm:
sudo npm install -g wsl-open
But there is also a non-npm installation described on their GitHub page, if you're not into node.
Port Fowards: Reaching the Outside World
While WSL normally forwards network ports to Windows automatically (though it occasionally hiccups 🤷♂️), external access remains challenging.
This can be frustrating when you need SSH access or want to quickly share files via a temporary web server.
Here's a PowerShell script that solves this limitation, allowing direct port forwarding to WSL (also available on GitHub):
# WSL2 network port forwarding script v1
# for enable script, 'Set-ExecutionPolicy -ExecutionPolicy Bypass -Scope CurrentUser' in Powershell,
# for delete exist rules and ports use 'delete' as parameter, for show ports use 'list' as parameter.
# written by Daehyuk Ahn, Aug-1-2020
# Display all portproxy information
If ($Args[0] -eq "list") {
netsh interface portproxy show v4tov4;
exit;
}
# If elevation needed, start new process
If (-NOT ([Security.Principal.WindowsPrincipal] [Security.Principal.WindowsIdentity]::GetCurrent()).IsInRole([Security.Principal.WindowsBuiltInRole]::Administrator))
{
# Relaunch as an elevated process:
Start-Process powershell.exe "-File",('"{0}"' -f $MyInvocation.MyCommand.Path),"$Args runas" -Verb RunAs
exit
}
# You should modify '$Ports' for your applications
$Ports = (667)
# Check WSL ip address
#wsl /bin/sh -c "ip route get 1 | grep 1. | awk '{print \`$3}'" | Set-Variable -Name "WSL"
#wsl hostname -i | Set-Variable -Name "WSL"
$WSL = wsl bash -c "ifconfig eth0 | grep 'inet ' | awk '{print \`$2}'"
echo $WSL
$found = $WSL -match '\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}';
if (-not $found) {
echo "WSL2 cannot be found. Terminate script.";
exit;
}
# Remove and Create NetFireWallRule
Remove-NetFireWallRule -DisplayName 'WSL 2 Firewall Unlock';
if ($Args[0] -ne "delete") {
New-NetFireWallRule -DisplayName 'WSL 2 Firewall Unlock' -Direction Outbound -LocalPort $Ports -Action Allow -Protocol TCP;
New-NetFireWallRule -DisplayName 'WSL 2 Firewall Unlock' -Direction Inbound -LocalPort $Ports -Action Allow -Protocol TCP;
}
# Add each port into portproxy
$Addr = "0.0.0.0"
Foreach ($Port in $Ports) {
iex "netsh interface portproxy delete v4tov4 listenaddress=$Addr listenport=$Port | Out-Null";
if ($Args[0] -ne "delete") {
iex "netsh interface portproxy add v4tov4 listenaddress=$Addr listenport=$Port connectaddress=$WSL connectport=$Port | Out-Null";
}
}
# Display all portproxy information
netsh interface portproxy show v4tov4;
# Give user to chance to see above list when relaunched start
If ($Args[0] -eq "runas" -Or $Args[1] -eq "runas") {
Write-Host -NoNewLine 'Press any key to close! ';
$null = $Host.UI.RawUI.ReadKey('NoEcho,IncludeKeyDown');
}
Pro tip: Avoid using port 22 for your SSH server, as the native Windows SSH server will intercept these connections.
[Optional] Custom Kernel: For the Power Users
While most users won't need a custom kernel, it's essential for specific use cases like running SocketCAN for car hacking. Here's how to build and install your own kernel:
#get kernel version
uname -r
5.10.60.1-microsoft-standard-WSL2
# get matching version, this is mine
wget https://github.com/microsoft/WSL2-Linux-Kernel/archive/refs/tags/linux-msft-wsl-5.10.60.1.tar.gz
#extract it (change to your kernel version)
tar -xf linux-msft-wsl-5.10.60.1.tar.gz
# build linux/modules
# change to the folder tar extracted too, yours might be different
cd WSL2-Linux-Kernel-linux-msft-wsl-5.10.60.1/
cat /proc/config.gz | gunzip > .config
make prepare modules_prepare -j $(expr $(nproc) - 1)
# select your drivers/modules here
make menuconfig -j $(expr $(nproc) - 1)
make modules -j $(expr $(nproc) - 1)
sudo make modules_install
make -j $(expr $(nproc) - 1)
sudo make install
# copy it to windows drive, change <yourwindowsloginname> to your windows users
cp vmlinux /mnt/c/Users/<yourwindowsloginname>/
#create this file
vim /mnt/c/Users/<yourwindowsloginname>/.wslconfig
#with these contents
[wsl2]
kernel=C:\\Users\\<yourwindowsloginname>\\vmlinux
# exit wsl
wsl.exe --shutdown