After several trials with native Windows, WSL-2 and docker containers, I finally decided to base my development environment inside WSL-2. WSL stands for Windows Subsystem for Linux, it runs a native Linux distribution inside Windows.
I have one WSL distribution as my primary shell for day to day tasks and one distribution per big project I'm working on. Here's how I usually setup a new project.
Introduction
I noticed that without special care to the programs and dependencies I install on my machine, the more projects I work on, the messier my OS gets. Particularly when working on two projects that require different versions of the same tools or programs. Luckily, most languages mitigate this issue using virtual environments (pip, conda, npx, etc.)... But there are often cases when I need something that can't be managed by a language's virtual environment.
I tried to find a uniform approach where every project would be isolated from the OS in a uniform manner. A theoretically perfect approach would be to spin up a docker container pre-configured with the development environment for each project. That way, no need to pollute the host with dependencies and languages versions. And this would also allow to run / restart the project several years later without worrying about everything being broken due to different versions of everything — which could be a real issue: as of today I can't run my first C/C++ programs due to non-existent dynamic libraries.
The operating system: Windows 10
I'm a big fan of Linux and if it weren't for missing drivers, I'd be running one of its distributions right now. But some components on my PC are not well handled on Linux so I'm stuck on Windows 10. Switching from MacOS & Linux to Windows a few years ago was extremely painful, but I finally getting used to it and I even started learning PowerShell (which is pretty great).
The major drawback with Windows for developers is that most installation or configuration instructions are written for Linux. A readme on GitHub is usually not written for chocolatey
and powershell
but rather for apt-get
and bash
.
The trick: WSL-2
But there is WSL-2, the Windows Subsystem for Linux, a lightweight virtual machine running a Linux Kernel created by Microsoft (WSL2-linux-kernel) to embed Linux inside Windows. It's not perfect (yet) but it works great. According to here and here using WSL-2 to compile java/maven projets could even be faster than using java on Windows (!!). These pages benchmark the performance of WSL-2 vs Windows and native Ubuntu. I'm very surprised to see that in some benchmarks, WSL-2 perform better than Windows or native Ubuntu. This article on Ulsoy's blog is an interesting read about his experience using WSL.
Let's setup a new development environment in WSL-2.
Requirements
First, install WSL-2.
Then you need a clean distribution to import into WSL. Here's how to create one easily: Download your distribution of choice from the App Store (I chose Ubuntu 20.04 LTS). Open the newly installed distribution once, and immediately close it to register the distribution inside WSL.
Open a new PowerShell terminal, list the distributions available using the following command and find the one you just installed:
wsl --list
Then, export it to create an untouched copy of the distribution (In my case, it's called Ubuntu
):
mkdir ~\Documents\wsl-distributions
wsl --export Ubuntu ~\Documents\wsl-distributions\ubuntu-20.04LTS.tar
Now, we're ready to create a new project.
Setting up a new project
When working on a new project big enough to justify having its own environment, I create a new WSL distribution for the project. To do so, I'll simply import a copy of the pristine Ubuntu distribution created in the previous section:
wsl --import ProjectName ~\AppData\Local\Packages\WSL.ProjectName ~\Documents\wsl-distributions\ubuntu-20.04LTS.tar
To start the distribution, use this command:
wsl -d ProjectName
This will open a new root terminal inside the distribution. Let's create a non-root user and configure it as the default user for this distribution. To do so, run these command inside the root WSL terminal:
useradd -s /bin/bash -d /home/user/ -m -G sudo user
passwd user
printf "[user]\ndefault=user\n" >> /etc/wsl.conf
Then exit the terminal, and inside powershell, restart the distribution:
wsl --terminate ProjectName
When reopening the distribution, you should be logged in as the newly created user. As we saw earlier, type this line into PowerShell to open the distribution:
wsl -d ProjectName
And that's it, you now have a new distribution that you can setup like any other.
Additional configuration
Shell prompt
To avoid mixing up my terminals, I like to edit my shell's prompt to display my distribution's name. To do so, edit the PS1
variable in your .bashrc
:
if [ "$color_prompt" = yes ]; then
PS1='${debian_chroot:+($debian_chroot)}\[\033[01;32m\]\u@$WSL_DISTRO_NAME\[\033[00m\]:\[\033[01;34m\]\w\[\033[00m\]\$ '
else
PS1='${debian_chroot:+($debian_chroot)}\u@$WSL_DISTRO_NAME:\w\$ '
fi
unset color_prompt force_color_prompt
# If this is an xterm set the title to user@disro-name:dir
case "$TERM" in
xterm*|rxvt*)
PS1="\[\e]0;${debian_chroot:+($debian_chroot)}\u@$WSL_DISTRO_NAME: \w\a\]$PS1"
;;
*)
;;
esac
Winhome link
To ease access to the files inside Windows (for instance, to copy downloads into WSL), I like to create a shortcut as follows (change julien
by your windows username):
ln -s /mnt/c/Users/julien ~/winhome
Graphical applications
It is possible to run graphical applications inside WSL. To do so, you need to install an X-Server on windows and configure the WSL distribution to connect to this server.
I use X410. Here's how to set it up for WSL-2. Once the X-Server is ready, edit your WSL environment to connect to it:
export DISPLAY=$(cat /etc/resolv.conf | grep nameserver | awk '{print $2; exit;}'):0.0
Custom keyboard layout
When running GUI apps through the X-Server, the keyboard layout needs to be installed in the distribution. Here's how I setup my Colemak layout:
sudo apt install x11-xkb-utils x11-xserver-utils
wget https://colemak.com/pub/unix/colemak-1.0.tar.g
tar -xvf colemak-1.0.tar.g
cd colemak-1.0/
setxkbmap us; xmodmap xmodmap/xmodmap.colemak && xset r 66
Configure ssh keys
Generate a new SSH key:
ssh-keygen -t ed25519 -C "$USER@$WSL_DISTRO_NAME"
To copy the newly created public key to the clipboard, use this command:
cat ~/.ssh/id_ed25519.pub | clip.exe
Then, follow these instructions to add the newly created key to your GitHub account.
Instead of the traditional ssh-agent
, it is more convenient to use keychain
inside WSL: (copied from this source)
sudo apt-get install keychain
Then, edit your ~/.bashrc
file to load the keys automatically:
# For Loading the SSH key
/usr/bin/keychain --nogui $HOME/.ssh/id_ed25519
source $HOME/.keychain/$HOSTNAME-sh
Tips
Access Windows clipboard
To access Windows clipboard, use the clip.exe
executable. For instance:
echo "test" | clip.exe