DEV Community

Cover image for WSL2, zsh, and docker. Linux through Windows.
Nicky Meuleman
Nicky Meuleman

Posted on • Originally published at nickymeuleman.netlify.com on

WSL2, zsh, and docker. Linux through Windows.

Compromises are great. When it comes to technology, having your cake and eating it too is better.

The machine I normally use for development broke.
The Windows Subsystem for Linux version 2 just came out, so I decided to set up another machine with that. When all was said and done, it was nothing short of awesome. I just booted a full-stack application that uses docker from an Oh My ZSH terminal window inside of VSCode. It booted faster than it ever had natively on Windows. I'm using Windows 10 Home, that means the hyper-V virtualization technology normally isn't available. But WSL2 lets you take advantage of it anyway (if your hardware supports it).

This post describes the steps I went through to set that up.

It's going to be a long one, so buckle up! 💪

Install the Insider preview

As of writing, WSL2 is available in the latest release of the insider preview.
If it's not installed, doing so is fairly straightforward.

  • Look for the insider programme and follow the steps to activate it.

As of writing, you will have to choose the fast ring of updates when prompted.

insider programma

  • Run Windows update

Windows update installing the insiders build

After a minor test of your patience and a few reboots. A watermark that displays the version you just installed is visible in the lower right corner of your desktop.

watermark

Activate optional features

WSL and WSL2 use some features that aren't activated by default, so enabling those is necessary.

This is possible through a GUI, by going to "turn Windows features on or off" or through an elevated Powershell prompt.

  • The GUI option:

Turn Windows features on or off

To use WSL, enable the aptly named "Windows Subsystem for Linux" feature.

Windows Subsystem for Linux feature

  • Through Powershell:


Enable-WindowsOptionalFeature -Online -FeatureName Microsoft-Windows-Subsystem-Linux


Enter fullscreen mode Exit fullscreen mode

Regardless of the option you chose, a reboot is required.

Feature for WSL2

That was enough for WSL1.
To use WSL2, first make sure virtualization is enabled in your BIOS.

WSL2 uses the hyper-V technology. That technology is normally only available on Windows 10 pro, but Windows 10 home can also use it for WSL2.

Enabling virtualization in the BIOS looks different for most motherboard brands.

On my MSI board the option was called "Virtualization Technology" and was hidden in the overclocking settings.

Next: enabling another optional feature in Windows!

Same story here, either use the GUI or an elevated Powershell window.

The option to enable is called the "virtual machine platform".

  • GUI

virtual machine platform feature

  • Powershell


Enable-WindowsOptionalFeature -Online -FeatureName VirtualMachinePlatform


Enter fullscreen mode Exit fullscreen mode

Install a distro

Once that reboot is done, you can go to the Microsoft store and install your favourite Linux distribution. I went with Ubuntu, because a lot of install instructions and other documentation are written for that distro.

Ubuntu in the Microsoft store

On the first boot of the distro you just installed (which presents itself as a terminal window), you'll be asked to enter a password for when you want to do stuff as a super user (sudo).

WSL1 to WSL2

To check which version of WSL is installed you can run a command in Powershell.



wsl --list --verbose
# or
wsl -l -v


Enter fullscreen mode Exit fullscreen mode

If the number for the version is 2, all systems go!

If not, convert that puppy from 1 to 2.



wsl --set-version <distro-name> 2
# in my case
wsl --set-version Ubuntu 2


Enter fullscreen mode Exit fullscreen mode

The output will tell you that this operation might take a while.

It's not one of those that says that only to finish 5 seconds later. It took about 10 minutes here.

Converting a distro from WSL1 to WSL2

At this point, WSL2 is ready to go.

Opening the distro you installed will show a bash prompt.

Windows Subsystem for Linux 2 comes with a real Linux kernel.

Previously there was a kernel compatibility layer that could not do quite as much.

In the words of a certain wooden puppet, it is now a real boy.

Pinocchio is a real boy

Users of WSL2 are encouraged to place their files inside the Linux root file system.

That way they benefit from file performance increases compared to WSL1.

In WSL2 you can now access files from Linux in Windows and the other way around.

Modifying Linux files from from Windows in WSL1 was always warned against, as this could cause bad things to happen. Whoooo, spooky 👻 (but, really, it was a bad idea.)

More details on changes are available in Microsoft's WSL2 release blogpost

Installing tools

Let's start loading up our environment with some needed tools.
A few tools still need to be installed on the Windows side, the rest are all Linux tools.

The two I'll install for Windows are: VSCode and git for Windows.
Remember to set the autocrlf setting to input for git. VSCode handles it well.

Open a terminal in Windows!



git config --global core.autocrlf input


Enter fullscreen mode Exit fullscreen mode

Before beginning to install Linux tools, we'll update our already installed packages.

From this point on, the action happens in your Linux terminal!



sudo apt update
sudo apt upgrade


Enter fullscreen mode Exit fullscreen mode

More preparation, installing build tools for node-gyp



sudo apt install build-essential


Enter fullscreen mode Exit fullscreen mode

Git

This one should also be installed on the Linux side.



sudo apt install git


Enter fullscreen mode Exit fullscreen mode

After installing git, remember to configure it.

Especially setting the autocrlf setting to input is important here.



git config --global core.autocrlf input


Enter fullscreen mode Exit fullscreen mode

Node & NPM

You can install it as a standalone package.

Now we can harness all those Linux-y tools, I'll use nvm instead to make using different versions easier.

The nvm repo has excellent installation instructions.



curl -o- https://raw.githubusercontent.com/nvm-sh/nvm/v0.34.0/install.sh | bash


Enter fullscreen mode Exit fullscreen mode

Restart your terminal after the install.

To confirm the installation was successfull:



command -v nvm


Enter fullscreen mode Exit fullscreen mode

It should return: nvm

That's all, no version number, just that string.

To install the latest the latest stable version of node:



nvm install node # "node" is an alias for the latest version


Enter fullscreen mode Exit fullscreen mode

When node releases a new version, you can run that same command again.

You'll need to tell nvm which version of node you want to use.

So next time you boot your Linux distro, you'll have to use.



nvm use node


Enter fullscreen mode Exit fullscreen mode

When the project you are working on requires a different version of node, specify that one.



nvm use v<version number>
# or if the project has a valid .nvmrc file
nvm use


Enter fullscreen mode Exit fullscreen mode

Having to do that manually seems annoying right?

Many solutions to this annoyance exist. Later in this post the annoyance will be "fixed".

Docker

  • Kick things off by updating the packages index and installing dependencies.


sudo apt update
sudo apt install apt-transport-https ca-certificates curl software-properties-common


Enter fullscreen mode Exit fullscreen mode
  • Add Dockers's official GPG-key.


curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo apt-key add -


Enter fullscreen mode Exit fullscreen mode
  • Verify this by running:


sudo apt-key fingerprint 0EBFCD88


Enter fullscreen mode Exit fullscreen mode

You should see the full key in the output.



9DC8 5822 9FC7 DD38 854A E2D8 8D81 803C 0EBF CD88


Enter fullscreen mode Exit fullscreen mode
  • Add the Docker repository to your list of repositories.


sudo add-apt-repository "deb [arch=amd64] https://download.docker.com/linux/ubuntu $(lsb_release -cs) stable"


Enter fullscreen mode Exit fullscreen mode
  • Update the list of repositories again and install Docker CE.


sudo apt update
sudo apt install docker-ce


Enter fullscreen mode Exit fullscreen mode

Normally, the docker engine starts automatically after the install.

For me that was not the case so I started it manually.



sudo service docker start


Enter fullscreen mode Exit fullscreen mode
  • Verify Docker CE was installed correcly by booting up their hello-world container.


sudo docker run hello-world


Enter fullscreen mode Exit fullscreen mode

Docker Compose

As a handy tool for managing docker containers, docker-compose is frequently installed alongside docker-ce.

  • Download the current stable release and place it in the /usr/local/bin folder.


sudo curl -L "https://github.com/docker/compose/releases/download/1.24.0/docker-compose-$(uname -s)-$(uname -m)" -o /usr/local/bin/docker-compose


Enter fullscreen mode Exit fullscreen mode
  • Make the file executable.


sudo chmod +x /usr/local/bin/docker-compose


Enter fullscreen mode Exit fullscreen mode
  • Verify the installation.


docker-compose --version
# output: docker-compose version 1.24.0, build 0aa59064


Enter fullscreen mode Exit fullscreen mode

Yarn

Yarn is a package manager for JavaScript made by Facebook.

  • Add their gpg key.


curl -sS https://dl.yarnpkg.com/debian/pubkey.gpg | sudo apt-key add -


Enter fullscreen mode Exit fullscreen mode
  • Add their repository.


echo "deb https://dl.yarnpkg.com/debian/ stable main" | sudo tee /etc/apt/sources.list.d/yarn.list


Enter fullscreen mode Exit fullscreen mode
  • Update the list of repositories and install Yarn.

Skip installing node with --no-install-recommends when using nvm



sudo apt update
sudo apt install --no-install-recommends yarn


Enter fullscreen mode Exit fullscreen mode
  • Verify the installation.


yarn --version


Enter fullscreen mode Exit fullscreen mode

A better terminal

When you open your terminal there are actually 2 sides at work.

The thing you see and type into, the terminal.

The thing that terminal communicates with and does most of the work, the shell.

Let's face it, the terminal that ships with Windows is pretty lackluster.

Good news: they are coming out with a new one and it looks really awesome!

In anticipation of that release, I'm not going to change much there. I'll use the one that's integrated into VSCode most of the time anyway.

edit 3 july: A preview is available in the Windows store. I tried it, and it's great!

Change integrated VSCode terminal

VSCode's integrated terminal is a great productivity booster.

Let's use the brand new Linux shell in there.

When opening the integrated terminal, you can choose wich one to use as the default one.

Select WSL from the resulting list of options and you are done!

select terminal in Visual Studio Code

Alternatively, edit the settings.json to point to the correct location.



"terminal.integrated.shell.windows": "C:\\WINDOWS\\System32\\wsl.exe"


Enter fullscreen mode Exit fullscreen mode

ZSH

I chose ZSH to replace the standard bash shell that opens when clicking the Ubuntu icon in the start menu.

Installing it is a oneliner thanks to the package manager in Ubuntu.



sudo apt install zsh


Enter fullscreen mode Exit fullscreen mode

When you launch Ubuntu, you'll still see the usual bash prompt.

To enter the zsh shell from that familiar bash prompt:



zsh


Enter fullscreen mode Exit fullscreen mode

The first time this launches a quick configuration wizard will be shown.

The choice here doesn't matter all that much, sinc the resulting file .zshrc will be overwritten when we install oh-my-zsh. I chose the option 2 anyway and went with the defaults.

zsh-install

Typing zsh into bash every time we launch it gets old quick.



cd $home #navigate to your home directory on Linux
code .bashrc #open the bash configuration file in visual studio code


Enter fullscreen mode Exit fullscreen mode

To automatically launch zsh when you open the terminal, add this to your .bashrc



# Launch Zsh
if test -t 1; then
exec zsh
fi


Enter fullscreen mode Exit fullscreen mode

Oh My ZSH

This extension to zsh has one of the best URLs out there: ohmyz.sh

It will also enable a huge list of nice features, which is more important.

Installing oh-my-zsh is a oneliner.



sh -c "$(curl -fsSL https://raw.github.com/robbyrussell/oh-my-zsh/master/tools/install.sh)"


Enter fullscreen mode Exit fullscreen mode

This will also replace that .zshrc file we initialised earlier.

Enjoy the cool ASCII art signalling a successful installation!

Theme oh-my-zsh

oh-my-zsh comes with lots of fancy themes, so let's install a pretty one!

Take a look at a list of them.

I like the agnoster one, so that's what I'll go with.

Edit the .zshrc file to enable it.

This file is also located in your Linux home directory (cd $home to go there).



# .zshrc
# change the default theme
ZSH_THEME="robbyrussell"
# to the chosen theme
ZSH_THEME="agnoster"


Enter fullscreen mode Exit fullscreen mode

restart your terminal for it to take effect.

Powerline fonts

Aaaaaaaaaah, it's ... broken. 😥

ugly oh my ZSH

That's partly because this is a fancy prompt that needs a Powerline-patched font to render correctly.

You can either download the specific font you want and install it that way (double clicking on the file and hitting the install button), or use the install script to install them all at once.

To install them all at once first clone that repo.

Then open an elevated Powershell window.

To be able to execute the install.ps1 file, we need to open up the execution policy temporarily.



Set-ExecutionPolicy Bypass


Enter fullscreen mode Exit fullscreen mode

Now navigate to the cloned repo and execute the install script.



.\install.ps1


Enter fullscreen mode Exit fullscreen mode

You'll see the same thing happening as you would when downloading and installing each font seperatly, but of course much quicker.

Don't forget to close down the execution policy again immediately after!



Set-ExecutionPolicy Default


Enter fullscreen mode Exit fullscreen mode

After installing the fonts, setting them in your terminal application changes the weird boxes to icons.

Note that the standard terminal in Windows still doesn't work quite right after that. It has many limitations, this not working completely is just one of them.

As stated before, I'm mainly going to use the terminal inside VSCode anyway, so I'm leaving the standard terminal behind.

After setting the terminal font in VSCode, all icons show up beautifully.

The colors when listing directories and files with the ls command still look, euuuhm, suboptimal.

ugly dircolors

dircolors

To replace those ugly colors, something called dircolors may be used.

I'll install the popular solarized dircolors

Pick the theme you want and download the file to your home directory.



curl https://raw.githubusercontent.com/seebi/dircolors-solarized/master/dircolors.ansi-dark --output ~/.dircolors


Enter fullscreen mode Exit fullscreen mode

Add a line to the bottom of your zsh configuration file to use what you just downloaded.



# load dircolors
eval `dircolors ~/.dircolors`


Enter fullscreen mode Exit fullscreen mode

Much better, it looks great now!

pretty-terminal

Plugins for oh-my-zsh

By itself, oh-my-zsh is already feature-rich. For further productivity increases, plugins are there to help.

Many of those plugins ship alongside oh-my-zsh, making installing them as easy as adding a line to .zshrc.

Others require a bit more effort, let's start with those!

Syntax Highlighting

zsh-syntax-highlighting is a handy plugin that prevents syntax errors by highlighting valid commands in green and invalid ones in red.

To install the plugin first clone the repo.

Then add the script to your .zshrc.



# inside .zshrc add
source <path-to-the-script>
# I cloned the repo to the .zsh folder, so for me it was
source ~/.zsh/zsh-syntax-highlighting/zsh-syntax-highlighting.zsh


Enter fullscreen mode Exit fullscreen mode

Auto Suggestions

zsh-autosuggestions makes typing the same command over and over much quicker by suggesting what you could type next. These suggestions are based on command history.

Installing it follows the same pattern as the plugin we installed above.

First clone the repo, then add a line to .zshrc



# .zshrc
source <path-to-the-script>
# I cloned the repo to the .zsh folder, so for me it was
source ~/.zsh/zsh-autosuggestions/zsh-autosuggestions.zsh


Enter fullscreen mode Exit fullscreen mode

pre-installed plugins

A list of the plugins that ship with oh-my-zsh can be viewed on this Github page.

Each one should have a README.md that tells you more about what it does and how to activate the plugin.

Most of the time, activating the plugin requires you to add it to the list of plugins in .zshrc.

This is what I ended up with:



plugins=(
    git
    node
    npm
    npx
    nvm
    z
)


Enter fullscreen mode Exit fullscreen mode

The plugin I would like to call out here is z.

It make navigating to frecent folders easy.

You read that right, it's not a typo.
It's a contraction of frequent and recent.

For example, my blog is located at ~/projects/nicky-blog.
If I type z blog, z will take me there.

Result

Whew! That was quite the journey 😅💦

The result is very powerful, and it looks good too! 🎊🎉🎉🎉🎊

the end result

Top comments (11)

Collapse
 
mhsangar profile image
Mario Sánchez García • Edited

Hi Nick!

Thanks a lot for the article, I've been following all the steps and I finally made it to the end 🎉🎉 I used Oh My Zsh before with the agnoster theme, so I decided to change it to powerline-go. You need Go in order to use it, but it's looks awesome 🙏

Here is the final result:

Preview of final result

Collapse
 
therakesh profile image
Rakesh Mandal 🗯️

Hi, this looks cool. Could you please show me the step to config it (powerline-go)? I'm a bit confused here.

Help appreciated

Collapse
 
nickymeuleman profile image
Nicky Meuleman

Hi Mario
Yay 🎉! That looks very nice! Lots of useful info displayed! (love the directory name btw)

Collapse
 
pellea profile image
Adrien Pellegrini

Nice article!

If you want to make it works in a "normal" console, you can install the Fira Code font (github.com/tonsky/FiraCode) and use it in the new Windows Terminal. It works fine with that font.

The only issue I have is that the git plugin is super slow with zsh.

Collapse
 
nickymeuleman profile image
Nicky Meuleman

Thank you!

That font is very nice. Using it as main editor font. Really liking the ligatures it has.

Collapse
 
giorgiobertolotti profile image
Giorgio Bertolotti

I'm using the z plugin since I read this article and I'm in love, thanks! ❤️

Collapse
 
elanhasson profile image
Elan Hasson • Edited

In VS Code, which font name should go here?
vs code settings

Collapse
 
elanhasson profile image
Elan Hasson • Edited

You have to put ProFont for Powerline Regular as the font there. You also need to set that Fira Code font in the Windows Terminal config.

Collapse
 
nickymeuleman profile image
Nicky Meuleman

You got it!

Hope you are liking the setup.

Collapse
 
_hs_ profile image
HS

These:
"
wsl --list --verbose

or

wsl -l -v
"
are not available in version 1 and won't work but it's an indicator that it's not v2

Collapse
 
nickymeuleman profile image
Nicky Meuleman

Good observation!

You'll need Windows build 18917 for those arguments to work, the build needed to make using WSL2 possible.
docs.microsoft.com/en-us/windows/w...