A complete guide to setup WSL (Windows Subsystem for Linux)

Qilong Liu
8 min readNov 4, 2023

WSL (Windows Subsystem for Linux) has various great advantages against dual-boot (installing Linux and Windows on the same computer), among them the most significant is that you can literally running both systems at the same time without the need to stop every software that’s running and reboot to another system. Procedure to set up a WSL is roughly the same as setting up a real Linux OS, therefore this guide can also be used as a reference to Linux setup. The specifications of WSL setup procedure are mainly in Install WSL, CUDA and PyTorch, _VTK with PyVista, and Remote development with SSH as described below.

Install WSL

Install WSL | Microsoft Learn

In PowerShell, run:

wsl --install

After restart the computer, the terminal will prompt you to set the user name and password for the WSL. Then you can then enter the linux subsystem by enter wsl in PowerShell or create a Ubuntu (WSL) shell in the terminal app.

P.S. Ubuntu is installed by default. You can also choose other distributions. In my case I choose Ubuntu 18.04 for VTK with PyVista:

wsl --install -d Ubuntu-18.04

Fish shell

Install

How to Install and Set Up the Fish Shell | by Saad Jamil | Medium

sudo apt-add-repository ppa:fish-shell/release-3
sudo apt-get update
sudo apt-get install fish

Theme

GitHub — oh-my-fish/theme-bobthefish: A Powerline-style, Git-aware fish theme optimized for awesome.

Use oh-my-fish to manage fish themes. Here we choose bobthefish:

curl https://raw.githubusercontent.com/oh-my-fish/oh-my-fish/master/bin/install | fish
omf install bobthefish
omf theme bobthefish

Configure fish by append the following contents to ~/.config/fish/config.fish:

set -g default_user na
set -g theme_display_hostname no
set -g fish_prompt_pwd_dir_length 0
set -g theme_display_git_default_branch yes
set -g theme_display_virtualenv no
set -g theme_display_date yes
set -g theme_date_format "+%a %H:%M"
set -g theme_newline_cursor yes
set -g theme_newline_prompt '> '

Enter fish automatically in Bash shell

Add this line to the end of ~/.bashrc:

# auto launch fish shell
fish

P.S. ~/.bashrc will be executed whenever a new bash shell is launched. Please note that all commands after this line will only be executed after you exit the fish shell. Therefore make sure that this line is at the end of ~/.bashrc.

Powerline font

To show bobthefish theme properly, we need to install Powerline fonts. I personally prefer Liberation Mono for Powerline, which is the default monospace font used in VS Code with Powerline style special symbols. In every places you'd like to use to terminal, e.g. VS Code's integrated terminal, set the font accordingly.

Take Windows Terminal app as an example: Settings > Profiles > Defaults > Appearance > Text > Font face. By the way I also prefer to set the color scheme as One Half Dark and set the background opacity as 80% with acrylic material enabled.

Git

git is pre-installed in WSL as well as most UNIX-like OSs, but it may be a legacy version. I prefer to update it first:

sudo add-apt-repository ppa:git-core/ppa
sudo apt-get update
sudo apt-get upgrade git

18.04 — sudo add-apt-repository hangs — Ask Ubuntu

P.S. If the first command hangs, sudo nano /etc/gai.conf and uncomment the row of precedence ::ffff:0:0/96 100.

Configuration

Let’s configure its default user name and user email. Noted that when you push commit to GitHub, the email will be used to identify your GitHub account:

git config --global user.name <name>
git config --global user.email <email>
git config --global init.defaultBranch main

Ignore Jupyter Notebook outputs

How to commit jupyter notebooks without output to git while keeping the notebooks outputs intact locally · GitHub

If you use Jupyter Notebook with Git, perhaps you’d be happy to keep the outputs of the code cells to be omitted for version tracking. In this case, first add a filter named strip-notebook-output globally to git:

git config --global filter.strip-notebook-output.clean 'jupyter nbconvert --ClearOutputPreprocessor.enabled=True --to=notebook --stdin --stdout --log-level=ERROR'

And then in each folder with Jupyter Notebook, run this to create a .gitattributes file to enable this filter on all Jupyter Notebooks:

echo "*.ipynb filter=strip-notebook-output" > .gitattributes

SSH key for GitHub

To authorize your operation on GitHub, you will also need to generate a ssh key:

ssh-keygen -t rsa -C "<email>"

And then you need to add it to your account: Settings > SSH and GPG keys > Add SSH Key. Fill the title as you like and paste the key with the content of the generated id_rsa.pub (NOT id_rsa!!). The content of id_rsa.pub can be easily accessed from command line:

cat ~/.ssh/id_rsa.pub

Python and Conda

Installing Miniconda

curl -sL "https://repo.anaconda.com/miniconda/Miniconda3-latest-Linux-x86_64.sh" > "Miniconda3.sh"
bash Miniconda3.sh

P.S. If you enter fish shell from bash shell, the previous commands only automatically initialize condafor bash shell. To initialize conda for fish shell as well, run the following command in bash shell:

conda init fish

P.S. At this stage, you may need to check ~/.bashrc and make sure the line of fish is at the end.

CUDA and PyTorch

CUDA

If the GPU driver and CUDA has been setup on Windows, they will also be available on WSL. Following the steps to install CUDA on WSL:

1. NVIDIA GPU Accelerated Computing on WSL 2 — CUDA on WSL 12.3 documentation

CUDA Toolkit 11.8 Downloads | NVIDIA Developer

wget https://developer.download.nvidia.com/compute/cuda/repos/wsl-ubuntu/x86_64/cuda-wsl-ubuntu.pin
sudo mv cuda-wsl-ubuntu.pin /etc/apt/preferences.d/cuda-repository-pin-600
wget https://developer.download.nvidia.com/compute/cuda/11.8.0/local_installers/cuda-repo-wsl-ubuntu-11-8-local_11.8.0-1_amd64.deb
sudo dpkg -i cuda-repo-wsl-ubuntu-11-8-local_11.8.0-1_amd64.deb
sudo cp /var/cuda-repo-wsl-ubuntu-11-8-local/cuda-*-keyring.gpg /usr/share/keyrings/
sudo apt-get update
sudo apt-get -y install cuda

16.04 — nvcc — version command says nvcc is not installed — Ask Ubuntu

Add cuda to path. Add the the following lines to ~/.bashrc:

# cuda path
export PATH="/usr/local/cuda-11.8/bin:$PATH"
export LD_LIBRARY_PATH="/usr/local/cuda-11.8/lib64:$LD_LIBRARY_PATH"

P.S. Again, please make sure that the line of fish is at the end of .bashrc.

Verification:

nvcc -V
nvidia-smi

P.S. nvidia-smi command seems works properly on Ubuntu 18.04 WSL but not on Ubuntu 22.04 WSL.

Create a virtual environment and install PyTorch

conda create -n pytorch python=3.10
conda activate pytorch
pip3 install torch torchvision torchaudio --index-url https://download.pytorch.org/whl/cu118

Verify installation:

python
>>> import torch
>>> torch.rand(5, 3)
>>> torch.cuda.is_available()

VTK with PyVista

In my use case, VTK (visualization toolkit) and pyvista (a 3D visualization package) is frequently used. However, since WSL doesn't carries GUI by default, setting up pyvista is a little bit tricky. If you don't use pyvista, please feel free to skip this section.

Installation — PyVista 0.42.3 documentation

Install necessary utils:

sudo apt update
sudo apt install python-qt4 libgl1-mesa-glx
sudo apt-get install xvfb

P.S. Since Ubuntu 22.04 no longer supports Qt4, you’d better choose Ubuntu 18.04 if you need this package.

Create a virtual environment for it and installed the necessary packages:

conda create --name vtk_env python=3.9
conda activate vtk_env
conda install nodejs
pip install jupyter pyvista trame

With JupyterLab

Before starting using PyVista, in terminal:

export DISPLAY=:99.0
export PYVISTA_OFF_SCREEN=true
Xvfb :99 -screen 0 1024x768x24 > /dev/null 2>&1 &
sleep 3

This will launch a X11 server for displaying the rendered scene as well as setup some necessary environmental variables. Then we can launch the Jupyter Lab server as usual:

jupyter lab --NotebookApp.token='' --no-browser --port=8888

P.S. If you connect to the WSL wish ssh, jupyter-server-proxy is needed to be setup:

Trame Jupyter Backend for PyVista — PyVista 0.42.3 documentation

!pip install jupyter-server-proxy

import pyvista as pv

pv.set_jupyter_backend('client')
pv.global_theme.trame.server_proxy_enabled = True
pv.global_theme.trame.server_proxy_prefix = '/proxy/'

With VS Code

In terminal, launch the X11 server for displaying the rendered scenes:

Xvfb :99 -screen 0 1024x768x24 > /dev/null 2>&1 &

And at the begging of each Notebook, setup the necessary environmental variables:

import os
import pyvista as pv

pv.set_jupyter_backend('static')
os.environ['DISPLAY'] = ':99.0'
os.environ['PYVISTA_OFF_SCREEM'] = 'true'

P.S. I haven’t yet figure out how to enable iterative plotting in VS Code environment. Therefore, I select the static backend.

Node.js and NVM

Installation of Node.js on Linux — GeeksforGeeks

sudo apt install npm

Verify installation:

node -v
npm -v

Remote development with SSH

SSH server

ubuntu — ssh installed but I get the error: Failed to start ssh.service: Unit ssh.service not found — Unix & Linux Stack Exchang

Though the SSH client is installed by default, the SSH server is needed to be explicitly installed to enable other computers to remotely access your WSL:

sudo apt-get install openssh-server
sudo dpkg-reconfigure openssh-server

Port number

bash — How to SSH into WSL from Windows on the same machine — Super User

Since the Windows system may have occupied port 22 for SSH, we need to specify another port for the WSL’s SSH:

sudo nano /etc/ssh/sshd_config

And then change the port number, say 2222.

Port 2222

You may also want to enable the password login:

PasswordAuthentication yes

After altering the configuration, restart ssh server:

sudo systemctl restart ssh

Key authentication

How To Configure SSH Key-Based Authentication on a Linux Server | DigitalOcean

Having to enter password for each ssh login is not very convenient. We can make our life a little bit easier by setting up key authentication. First generate a key:

ssh-keygen

It will prompt you to input the <key path> and the pass phrase. Then you need to add your key to your local ssh client:

ssh-add <key path>

Noted that you will need to add it again when you reboot your local machine. You may add this command to ~/.bashrc for convenience.

Then send the key to the remote server:

ssh-copy-id -i <key path> -p 2222 <address>

Noted the the -p argument is the port number of the remote server you set before. Moreover, the addr is the IP address of the remote server which can be check by ifconfig.

Before you can log in to the remote server without entering the password, you will need to enable key authentication first:

sudo nano /etc/ssh/sshd_config

And then change uncomment the row of KeyAuthentication yes. For security considerations, it's preferable to disable password authentication if you have already setup key authentication. Change the row of PasswordAuthentication yes to PasswordAuthentication no.

And then:

sudo systemctl restart sshd

If everything is setup well, you will no longer need to enter the password the next time you ssh into the remote machine.

NAT traversal with cpolar

cpolar下载与安装 — cpolar 极点云

curl -L https://www.cpolar.com/static/downloads/install-release-cpolar.sh | sudo bash

In terminal, setup token:

P.S. Your token is linked to your cpolar account.

cpolar authtoken <your privite token>

To set the tunnel to be a background service and automatically launch with reboots, we need to edit cpolar's configuration file.

4.2 默认配置文件路径 — cpolar 极点云

3.3 将隧道配置为后台服务 — cpolar 极点云

Open the configuration file:

sudo nano /usr/local/etc/cpolar/cpolar.yml

Edit the configuration. For example:

tunnels:
ssh:
addr: 2222
proto: tcp
region: hk

P.S. The addr should be the port number you set in /etc/ssh/sshd_config.

P.S. There are various region options: us,hk,cn,cn_vip.

And then restart cpolar. The tunnel will be automatically setup:

sudo systemctl restart cpolar

--

--