DEV Community

Cover image for The ultimate WSL2 setup
Peter Repukat
Peter Repukat

Posted on • Updated on

The ultimate WSL2 setup

This is a crosspost originally from my own blog


I often get asked by friends and workmates how my WSL setup, on my Machines for both, personal and professional work, looks likeand how I even use zsh as my native shell for Windows tasks.

Every time this happens, I link them to an old post of mine, accompanied by a giant wall of text since a lot has happened since then.

I recently (at the time of writing) changed the company I work for and Microsoft released Win11, now is a better time than ever to finally post again about my WSL setup (and maybe even keep it up to date?)

TL;DR

for everyone that doesn't feel like reading my gibberish:

Let me know if you think I'm missing something!

Setup

Terminal

Before starting with setting up WSL and the shell environment, I'd recommend getting a proper Terminal emulator.

Choices are not as limited anymore as they were a few years ago.
The "Windows Terminal" has a pretty good feature set that should be enough for regular use.

Best of all: It's fast!

It even got quake-mode not too long ago, and can replace the pesky default "conhost.exe".

It has become my go-to and only terminal emulator on Windows.

However, it lacks a few customizations options like auto-start in hidden-quake mode, and always on top separately for quake-mode and normal-mode instances.

If you need that, you can use ConEmu as it is still the most fully-featured Terminal emulator for Windows.

Be aware that it can be kinda slow, though.

Fonts

Next up, get proper fonts with a high number of glyphs (icons), like "nerd-fonts".

As there is no official all-in-one installer for Windows you can use your favorite Windows package-manager, or just opt to install a handful of select fonts as I did.

Windows Sudo

(Trust me, it's useful!)

I'd also strongly recommend you install gsudo, basically sudo for Windows.

If you're on Win11 you can just winget install gsudo in an elevated PowerShell.

After the installing, you can elevate any Windows process/command by just prefixing gsudo

WSL

I personally came to love Arch Linux and I think that its minimalist approach fits very well for being used in the WSL. Although Arch is not officially supported, you can use one of many distro-launchers/-installers to get it going.

I personally use ArchWSL as it's well maintained and I've never had much issue running it, even professionally.
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

With any recent version of WSL2, one of the few out-of-the-box issue is missing systemd.

This might not be that big of a deal when running the default Ubuntu flavor, but on Arch, it can be really painful.

Thankfully, the community has got our back and there are several alternatives you can run.

With them, one can even use docker, without the need to install docker-for-windows.

I personally use genie as it breaks the least of my stuff and is easy to set up and configure.

Currently, (and to my knowledge) only QT-based GUI programs don't work properly when started from a shell inside the genie-bottle.

At the time of writing, if you want wslg GUI support, you will need to enable the wslg-xwayland.socket systemd units manually:

systemctl enable wslg-xwayland.socket
Enter fullscreen mode Exit fullscreen mode

I've also decided to edit the default config of genie (/etc/genie.ini) and clone the windows-path, like WSL does without it, to provide a more seamless experience.

[genie]
secure-path=/lib/systemd:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin
unshare=/usr/bin/unshare
update-hostname=true
clone-path=true
clone-env=WSL_DISTRO_NAME,WSL_INTEROP,WSLENV,DISPLAY,WAYLAND_DISPLAY,PULSE_SERVER
systemd-timeout=240
resolved-stub=false
Enter fullscreen mode Exit fullscreen mode

File system gotchas

On recent Windows versions, File-explorer already provides access to Linux files and tries to provide a seamless experience.

However, it can lead to compatibility issues with some programs, so I think it's still best to just map the WSL files as a network drive.

If you use \\wsl.localhost\ as path for your network-drive, explorer will just let you do that.

When coming from the Linux-side, it's possible to project file-permissions and additional metadata to NTFS, but it's still not enabled by default 🤦‍♂️

When enabled, this will allow you, for example, to symlink your ssh-key-folder generated on Windows, eliminating the need to set up multiple keys for the same damn machine. To get that working, you need to edit the automount options in /etc/wsl.conf

Or you can just copy&pasta my config:

# 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
Enter fullscreen mode Exit fullscreen mode

USB-Support

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...

gsudo winget install --interactive --exact dorssel.usbipd-win
Enter fullscreen mode Exit fullscreen mode

...and if you're using Arch too, nothing more is required (required Ubuntu packages can be taken from M$s blog post)

In any elevated command-prompt you can now list compatible USB-devices and attach/detach them to/from WSL using usbipd wsl list and usbipd wsl attach --busid XX

If you've installed the aforementioned gsudo you can also just run the commands directly from WSL like this (or just make an alias which I prefer)

cmd.exe /c gsudo usbipd wsl list
cmd.exe /c gsudo usbipd wsl attach --busid X-X
Enter fullscreen mode Exit fullscreen mode

WSL-OPEN

Yet another tool I very strongly recommend is wsl-open.

It allows you to use Linux's standart xdg-open command for files and links, and they magically open with the corresponding native Windows application.

It really helps to get a more seamless experience, going so far that I use zsh in the WSL as my regular Windows shell.

You can just install it via npm

sudo npm install -g wsl-open
Enter fullscreen mode Exit fullscreen mode

But there is also a non-npm installation described on their GitHub page, if you're not into node.

Port Fowards

Normally, all network ports are forwarded to the Windows host, so that you can access webservers/databases and whatnot from Windows. I say normally, as it sometimes breaks for no reason(???)

What it doesn't allow you to do is make network services available from outside your machine. Total bummer if you want ssh-access to your machine, or just quickly share a few files to a colleague via some quickly spawned up webserver.

Luckily again, the community has got our backs again and there is a PowerShell script that allows one to forward any ports directly to WSL.

Here's a version that works with recent Arch versions in WSL, also found 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');
}
Enter fullscreen mode Exit fullscreen mode

Just make sure to edit the forwarded ports that you require.

One thing to note, though, is that you cannot run your ssh-server on the default port 22.
If you do, the native Windows ssh-server will just get the connection, instead of the one on your WSL.

Custom Kernel

Most people will not care about running a custom Kernel on WSL, however, if you need drivers that are not included by default, like SocketCan for when you're into car hacking there is no way around it.

Here are the basic instruction to get a custom Kernel up and running:

#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
Enter fullscreen mode Exit fullscreen mode

Missing something?

Am I missing something?
Let me know!

Discussion (0)