The ultimate WSL2 setup
Tags: wsl2, windows, setup, ultimate
Published: 2021-12-08 23:27:13

---
title: The ultimate WSL2 setup
published: true
description: My WSL2 dev setup
tags: #wsl2 #windows #setup #ultimate
cover_image: https://behind.flatspot.pictures/content/images/size/w2000/2021/12/2021-12-05_0225.png
---

This is a crosspost originally from [my own blog](https://behind.flatspot.pictures/the-ultimate-wsl2-setup/)

---

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:
 - Win 11 (wslg pre-setup)
 - [Windows Terminal](https://www.microsoft.com/p/windows-terminal/9n0dx20hk701?rtc=1&activetab=pivot:overviewtab)
 - [usbipd-win](https://github.com/dorssel/usbipd-win) (usb passthrough)
 - [ArchWSL](https://github.com/yuk7/ArchWSL)
 - [genie](https://github.com/arkane-systems/genie) (systemd)
 - zsh (with some plugins)
 - [gsudo](https://github.com/gerardog/gsudo) (sudo for windows)
 - [wsl-hello-sudo](https://github.com/nullpo-head/WSL-Hello-sudo) (using windows hello/fingerpint with wsl-sudo)
 - [wsl-open](https://github.com/4U6U57/wsl-open) (open any file/link with native windows executable)
 - [my dotfiles](https://1-3-3-7.dev/dotfiles/tree/wsl-arch)
 - Custom Kernel for car-hacking stuff

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](https://www.microsoft.com/p/windows-terminal/9n0dx20hk701?activetab=pivot:overviewtab)" has a pretty good feature set that should be enough for regular use.  
Best of all: It's fast!  
It even got [quake-mode](https://github.com/microsoft/terminal/blob/main/doc/specs/#653%20-%20Quake%20Mode/#653%20-%20Quake%20Mode.md) 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](https://conemu.github.io/) 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](https://www.nerdfonts.com/#home)".  
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](https://github.com/gerardog/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](https://github.com/yuk7/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](https://wsldl-pg.github.io/ArchW-docs/How-to-Setup/)
If you've never used WSL before or start with a fresh Windows install, use [Microsoft's guide](https://docs.microsoft.com/de-de/windows/wsl/install-win10#step-2---check-requirements-for-running-wsl-2) 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](https://github.com/arkane-systems/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:

```bash
systemctl enable wslg-xwayland.socket
```

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.

```ini
[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
```


### 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:

```ini
# 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

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.](https://devblogs.microsoft.com/commandline/connecting-usb-devices-to-wsl/)

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](https://github.com/dorssel/usbipd-win)_...

```powershell
gsudo winget install --interactive --exact dorssel.usbipd-win
```

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

```bash
cmd.exe /c gsudo usbipd wsl list
cmd.exe /c gsudo usbipd wsl attach --busid X-X
```

### WSL-OPEN

Yet another tool I very strongly recommend is [wsl-open](https://github.com/4U6U57/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

```bash
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

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](https://gist.github.com/Alia5/f32bf1440e5d705b8ede1a0269d985fc):

```powershell
# 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');
}
```

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:
```bash
#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
```

### Missing something?

Am I missing something?
Let me know!