Skip to content

Latest commit

 

History

History

wsl

Folders and files

NameName
Last commit message
Last commit date

parent directory

..
 
 
 
 
 
 
 
 
 
 

Windows Sub-System for Linux (WSL)

Contents

About

  • Working on Windows 10 with WSL
  • Having a visually nice terminal through Windows Terminal (Preview)
  • zsh as my main shell with oh-my-zsh as well
  • Using Docker and Docker Compose directly from zsh
  • Using VSCode (Insiders) directly from WSL 2

Specifications

  • Host: Windows 11 Pro x64
    • Ubuntu via WSL 2 (Windows Subsystem for Linux)
    • Docker Desktop
  • Terminal: Windows Terminal Preview
  • Shell: zsh
    • git
    • docker (works with Docker Desktop)
    • docker-compose (works with Docker Desktop)
  • Node.js (using nvm)
    • node
    • npm
    • yarn
  • IDE: VSCode Insiders and the Remote WSL Extension
  • WSL Bridge: allow exposing WSL 2 ports on the network

Installation

See Install WSL on Windows 10 | Microsoft Docs

  • From Windows:
    • Enable WSL Optional Feature via wsl --install (only works for Insider releases)
      • In order to use the wsl --install simplified install command, you must:
        • Join the Windows Insiders Program
        • Install a preview build of Windows 10 (OS build 20262 or higher).
        • Open a command line window with Administrator privileges
      • The --install command performs the following actions:
        • Enables the optional WSL and Virtual Machine Platform components
        • Downloads and installs the latest Linux kernel
        • Sets WSL 2 as the default
        • Downloads and installs a Linux distribution (reboot may be required)
      • By default, the installed Linux distribution will be Ubuntu. This can be changed using wsl --install -d <Distribution Name>. (Replacing <Distribution Name> with the name of your desired distribution.) Additional Linux distributions may be added to your machine after the initial install using the wsl --install -d <Distribution Name> command.
      • To see a list of available Linux distributions, enter wsl --list --online.
# install Ubuntu
wsl --install -d Ubuntu

# set WSL2 as default
wsl --set-default-version 2

# check status
wsl --status

# check for updates
wsl --update

# other commands:
# wsl --export
# wsl --import
# wsl --exec <command>

Legacy Installation

# ADMIN

# enable WSL feature via DISM
dism.exe /online /enable-feature /featurename:Microsoft-Windows-Subsystem-Linux /all /norestart

# enable virtualmachine platform for WSL2
dism.exe /online /enable-feature /featurename:VirtualMachinePlatform /all /norestart

# restart
Restart-Computer

# upgrade to WSL2 kernel:
wsl --update

# set default version
wsl --set-default-version 2

For direct download of Ubuntu from the Microsoft Store visit: Get Ubuntu - Microsoft Store.


  • Enable WSL 2 and update the linux kernel (Source)
# In PowerShell as Administrator

# Enable WSL and VirtualMachinePlatform features
dism.exe /online /enable-feature /featurename:Microsoft-Windows-Subsystem-Linux /all /norestart
dism.exe /online /enable-feature /featurename:VirtualMachinePlatform /all /norestart

# Download and install the Linux kernel update package
$wslUpdateInstallerUrl = "https://wslstorestorage.blob.core.windows.net/wslblob/wsl_update_x64.msi"
$downloadFolderPath = (New-Object -ComObject Shell.Application).NameSpace('shell:Downloads').Self.Path
$wslUpdateInstallerFilePath = "$downloadFolderPath/wsl_update_x64.msi"
$wc = New-Object System.Net.WebClient
$wc.DownloadFile($wslUpdateInstallerUrl, $wslUpdateInstallerFilePath)
Start-Process -Filepath "$wslUpdateInstallerFilePath"

# Set WSL default version to 2
wsl --set-default-version 2

Ubuntu Community Preview Distro

To install the latest Community Preview Version of Ubuntu you can simply visit Microsoft Store Link here: Get Ubuntu on Windows Community Preview - Microsoft Store

Alternatively, you can download the appxbundle directly via Invoke-RestMethod and install directly from the terminal (note however that you must have the Developer Mode features enabled to allow side-loading apps from appxbundle files)

Run the following:

# specify uri (retrieved via https://store.rg-adguard.net/)
$uri = "http://tlu.dl.delivery.mp.microsoft.com/filestreamingservice/files/97622db3-5fac-4245-86a5-e3c72c8242dc?P1=1630030809&P2=404&P3=2&P4=OkKbA8SXGdWWTnIMWGAoO9Z8cdKhk1JrDUvxVehBAXdFRl8GIrVXlUltUZHYbHMMfazBl1X3%2fg3XtperasA7AQ%3d%3d"

# may take a minute
Invoke-RestMethod $uri -OutFile "~/Downloads/Ubuntu-CommPrev.appxbundle"

# run the downloaded file
cd ~/Downloads
.\Ubuntu-CommPrev.appxbundle

Setup

# update, upgrade, autoremove
sudo apt -y update && sudo apt -y upgrade && sudo apt -y autoremove

# initial installations 
sudo apt install 

Install Common Dependencies

#!/bin/bash

sudo apt update && sudo apt install -y \
    build-essential \
    git \ 
    apt-transport-https \
    ca-certificates \
    curl \
    gnupg-agent \
    software-properties-common \
    git \
    make \
    tig \
    zsh

Setup GPG Key

Note: exporting already created GPG keys from windows first and then importing to WSL distro's user directory.

If you already have a GPG key, restore it. If you did not have one, you can create one.

Export from Windows

  • On windows, create a backup of a GPG key
    • gpg --list-secret-keys
    • gpg --export-secret-keys {{KEY_ID}} > private.key
  • Import the key to WSL:
    • gpg --import /mnt/c/users/<username>/private.key
  • Delete the private.key

Create a New Key

  • gpg --full-generate-key

Read GitHub documentation about generating a new GPG key for more details.

Setup Git

#!/bin/bash

# Set username and email for next commands
email="<email>"
username="<name>"
gpgkeyid="<gpg key>"

# Configure Git
git config --global user.email "${email}"
git config --global user.name "${username}"
git config --global user.signingkey "${gpgkeyid}"
git config --global commit.gpgsign true
git config --global core.pager /usr/bin/less
git config --global core.excludesfile ~/.gitignore_global
git config --global core.attributesfile ~/.gitattributes_global
git config --global color.ui "auto"
git config --global default.protocol "ssh"
git config --global init.defaultBranch "main"

# Generate a new SSH key
ssh-keygen -t rsa -b 4096 -C "${email}"

# Start ssh-agent and add the key to it
eval $(ssh-agent -s)
ssh-add ~/.ssh/id_rsa

# copy key to clipboard (need xclip)
sudo apt install xclip -y
cat ~/.ssh/id_rsa.pub | xclip -sel clip

# launch github to add ssh key to account
powershell.exe -Command 'start https://github.com/settings/ssh/new'

My .gitconfig

[user]
	email = [email protected]
	name = Jimmy Briggs
	signingKey = <REDACTED>
	autocrlf = input
[github]
	user = jimbrig
[default]
	protocol = ssh
[gpg]
	program = /usr/bin/gpg
[init]
	defaultBranch = main
[commit]
	gpgSign = true
[tag]
	forceSignAnnotated = true
[core]
	editor = code-insiders --wait --new-window
	excludesfile = ~/.gitignore_global
  	attributesfile = ~/.gitattributes_global
[diff]
	tool = code-insiders
	renames = copies
[difftool "code-insiders"]
	cmd = code-insiders --wait --diff $LOCAL $REMOTE
[merge]
	tool = code-insiders
	log = true
[mergetool "code-insiders"]
	cmd = code-insders --wait $MERGED
	trustexitcode = true
[color]
	ui = auto
[color "branch"]
    	current = yellow reverse
    	local = yellow
    	remote = green
[color "diff"]
    	meta = yellow bold
    	frag = magenta bold
    	old = red bold
    	new = green bold
[color "status"]
    	added = yellow
    	changed = green
    	untracked = cyan
    	branch = magenta
[help]
	autocorrect = 1
[apply]
	whitespace = fix
[rerere]
	enabled = true
[submodule]
	recurse = true

Link Git Config Files back to Dotfiles

#!/bin/zsh

# move from home to dotdir (since configured above)
mv ~/.gitconfig ~/dev/wsl-dotfiles/ubuntu-commprev/home/jimbrig/.gitconfig

# link back
ln -sf ~/dev/wsl-dotfiles/ubuntu-commprev/home/jimbrig/.gitconfig ~/.gitconfig

# add links for gitignore and gitattributes (global)
ln -sf ~/dev/wsl-dotfiles/ubuntu-commprev/home/jimbrig/.gitignore_global ~/.gitignore_global
ln -sf ~/dev/wsl-dotfiles/ubuntu-commprev/home/jimbrig/.gitattributes_global ~/.gitattributes_global

# push
cd ~/dev/wsl-dotfiles
git add ubuntu-commprev/home/jimbrig/**
git commit -m "add updated gitconfig"
git push --set-upstream origin main

Setup Shell with zsh

#!/bin/zsh

# Clone the dotfiles repository
mkdir -p ~/dev/wsl-dotfiles
git clone [email protected]:jimbrig/wsl-dotfiles.git ~/dev/dotfiles

# install zsh
sudo apt -y install zsh

# clone oh-my-zsh
git clone git://github.com/robbyrussell/oh-my-zsh.git ~/.oh-my-zsh

# Install some external plugins:
git clone https://github.com/zsh-users/zsh-autosuggestions ~/.zsh/zsh-autosuggestions
git clone https://github.com/zsh-users/zsh-completions ~/.oh-my-zsh/custom/plugins/zsh-completions
git clone https://github.com/zsh-users/zsh-syntax-highlighting.git ~/.zsh/zsh-syntax-highlighting

# Set Zsh as your default shell:
chsh -s /bin/zsh

# (optional) Install Antibody Plugin Manager
curl -sfL git.io/antibody | sudo sh -s - -b /usr/local/bin

# Add plugins to ~/.zsh_plugins.zsh using antibody
antibody bundle < ~/dev/wsl-dotfiles/zsh_plugins > ~/.zsh_plugins.zsh

# Link custom dotfiles
ln -sf ~/dev/wsl-dotfiles/ubuntu-commprev/home/jimbrig/.aliases.zsh ~/.aliases.zsh
ln -sf ~/dev/wsl-dotfiles/ubuntu-commprev/home/jimbrig/.p10k.zsh ~/.p10k.zsh
ln -sf ~/dev/wsl-dotfiles/ubuntu-commprev/home/jimbrig/.zshrc ~/.zshrc

# Create .screen folder used by .zshrc
mkdir ~/.screen && chmod 700 ~/.screen

# Change default shell to zsh
chsh -s $(which zsh)

Docker

Install Docker Desktop

  • Install Docker Desktop
  • Make sure that the "Use the WSL 2 based engine" option is checked in Docker Desktop settings
sudo cinst -y docker-desktop

Setup Docker CLI

#!/bin/zsh

# Add Docker to sources.list
curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo apt-key add -
versionCodename=$(cat /etc/os-release | grep VERSION_CODENAME | cut -d= -f2)
sudo add-apt-repository "deb [arch=amd64] https://download.docker.com/linux/ubuntu $(versionCodename) stable"

# Install tools
sudo apt update && sudo apt install -y \
    docker-ce

# Add user to docker group
sudo usermod -aG docker $USER

Node.js, NPM, and NVM

#!/bin/zsh

# Install NVM
curl -o- https://raw.githubusercontent.com/nvm-sh/nvm/v0.34.0/install.sh | zsh

# install node and npm
nvm install --lts
node --version && npm --version

# Update NPM
npm install -g npm

# Login
npm login

# View stars for reference
npm stars

# install some globals
npm install -g bower create-next-app create-react-app cross-env dbdocs doctoc eslint gulp jshiny npm-check-updates npm-check vercel yarn

# doctor
npm doctor

Github CLI

sudo apt-key adv --keyserver keyserver.ubuntu.com --recv-key C99B11DEB97541F0
sudo apt-add-repository https://cli.github.com/packages
sudo apt update
sudo apt install gh

Setup Windows Terminal

#!/bin/zsh

windowsUserProfile=/mnt/c/Users/$(cmd.exe /c "echo %USERNAME%" 2>/dev/null | tr -d '\r')

# Copy Windows Terminal settings
cp ~/dev/dotfiles/terminal-settings.json ${windowsUserProfile}/AppData/Local/Packages/Microsoft.WindowsTerminal_8wekyb3d8bbwe/LocalState/settings.json

WSL Bridge

When a port is listening from WSL 2, it cannot be reached. You need to create port proxies for each port you want to use. To avoid doing than manually each time I start my computer, I've made the wslb alias that will run the wsl2bridge.ps1 script in an admin Powershell.

#!/bin/zsh

windowsUserProfile=/mnt/c/Users/$(cmd.exe /c "echo %USERNAME%" 2>/dev/null | tr -d '\r')

# Get the hacky network bridge script
cp ~/dev/dotfiles/wsl2-bridge.ps1 ${windowsUserProfile}/wsl2-bridge.ps1

In order to allow wsl2-bridge.ps1 script to run, you need to update your PowerShell execution policy.

# In PowerShell as Administrator

Set-ExecutionPolicy -ExecutionPolicy RemoteSigned
PowerShell -File $env:USERPROFILE\\wsl2-bridge.ps1

Then, when port forwarding does not work between WSL 2 and Windows, run wslb from zsh:

#!/bin/zsh

wslb

Note: This is a custom alias. See .aliases.zsh for more details

Limit WSL 2 RAM consumption

#!/bin/zsh

windowsUserProfile=/mnt/c/Users/$(cmd.exe /c "echo %USERNAME%" 2>/dev/null | tr -d '\r')

# Avoid too much RAM consumption
cp ~/dev/dotfiles/.wslconfig ${windowsUserProfile}/.wslconfig

Note: You can adjust the RAM amount in .wslconfig file. Personally, I set it to 8 GB.

WSL Scratch Notes

Remove

Use rm -r to remove directories:

# remove directory 'dir'
rm -r dir

# remove file 'test'
rm test

# remove empty directories in dir
rm -d dir

Link

Use ln to make hardlinks and symlinks:

# create symlink from windows ~/Dev dir to WSL ~/dev/windev dir
ln -s /mnt/c/users/jimmy/dev ~/dev/windev

# need sudo for default hard links
sudo ln /etc/wsl.conf ~/.dotfiles/etc/wsl.conf

Tar and Unzip

# unzip via tar
tar xvf <path/to/file.tar.gz>

# install unzip
sudo apt install unzip

DOS vs. UNIX Line Ending Issues

Unfortunately, the programmers of different operating systems have represented line endings using different sequences:

  • All versions of Microsoft Windows represent line endings as CR followed by LF.
  • UNIX and UNIX-like operating systems (including Mac OS X) represent line endings as LF alone.

Therefore, a text file prepared in a Windows environment will, when copied to a UNIX-like environment such as WSL, have an unnecessary carriage return character at the end of each line. To make matters worse, this character will normally be invisible, though in some text editors it will show up as ^M or similar.

Symptoms

If you run a script initially created on windows with `` line ending support, you will see errors like this in WSL:

  • from install-homebrew.sh:
ERROR:
./install-homebrew-ubuntu.sh: line 4: $'\r':

ERROR:
./install-homebrew-ubuntu.sh: line 7: $'\r': command not found
./install-homebrew-ubuntu.sh: line 15: $'\r': command not found
./install-homebrew-ubuntu.sh: line 10: $'\r': command not found
./install-homebrew-ubuntu.sh: line 12: $'\r': command not found
./install-homebrew-ubuntu.sh: line 15: $'\r': command not found
./install-homebrew-ubuntu.sh: line 20: $'\r': command not found
/bin/bash: -c: line 856: syntax error: unexpected end of file

./install-homebrew-ubuntu.sh: line 17: $'\r': command not found. Did you mean gcc, gcc@9, gcc@8, gcc@7, gcc@6 or gcc@5?
  • from install-gh-cli.sh:
./install-github-cli.sh: line 2: $'\r': command not found
1.14.0
./install-github-cli.sh: line 4: $'\r': command not found
curl: (3) URL using bad/illegal format or missing URL
./install-github-cli.sh: line 6: $'\r': command not found
tar: gh_1.14.0\r_linux_amd64.tar.gz\r: Cannot open: No such file or directory
tar: Error is not recoverable: exiting now
./install-github-cli.sh: line 8: $'\r': command not found
cp: cannot stat 'gh_1.14.0'$'\r''_linux_amd64/bin/gh': No such file or directory
./install-github-cli.sh: line 10: $'\r': command not found
./install-github-cli.sh: line 11: gh: command not found
./install-github-cli.sh: line 12: $'\r': command not found
cp: cannot stat 'gh_1.14.0'$'\r''_linux_amd64/share/man/man1/*': No such file or directory
./install-github-cli.sh: line 14: $'\r': command not found

Solution: dos2unix

Source: [How do I fix "$'\r': command not found" errors running Bash scripts in WSL? - Ask Ubuntu](https://askubuntu.com/questions/966488/how-do-i-fix-r-command-not-found-errors-running-bash-scripts-in-wsl#:~:text=steeldriver is correct that the problem is that,is absent in traditional Unix-style line endings (LF).)

$'\r': command not found strongly suggests the issue is that you have used a Windows text editor that has saved your files with DOS-style CRLF line endings - see for example DOS vs. Unix Line Endings

Inside WSL:

sudo apt-get install dos2unix

Then,

dos2unix [file]

Full documentation:

man dos2unix

Here you can see it in action:

image-20210819020049489

now try to re-run scripts.

Permissions

After linking my ssh keys between windows and WSL via: ln /mnt/c/users/jimmy/.ssh ~/.ssh I received the error:

Warning: Permanently added the RSA host key for IP address '140.82.113.3' to the list of known hosts.
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
@         WARNING: UNPROTECTED PRIVATE KEY FILE!          @
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
Permissions 0777 for '/home/jimbrig/.ssh/id_ed25519' are too open.
It is required that your private key files are NOT accessible by others.
This private key will be ignored.
Load key "/home/jimbrig/.ssh/id_ed25519": bad permissions
[email protected]: Permission denied (publickey).
fatal: Could not read from remote repository.

Please make sure you have the correct access rights
and the repository exists.

Need to change from a symlink to hardlink and/or jsut copy via cp:

rm -r ~/.ssh
cp -r /mnt/c/users/jimmy/.ssh ~/.ssh

Then fix permissions via:

chmod 600 ~/.ssh/id_rsa

What this does is set Read/Write access for the owner, and no access for anyone else. That means that nobody but you can see this key. The way god intended.

Source Sharing SSH keys between Windows and WSL 2 | Windows Command Line (microsoft.com)

Now it works: ✔️

image-20210819023041641

Fix GPG keys also:

%PATH%

Warning: /home/linuxbrew/.linuxbrew/bin is not in your PATH.

echo 'eval "$(/home/linuxbrew/.linuxbrew/bin/brew shellenv)"' >> /home/jimbrig/.profileeval "$(/home/linuxbrew/.linuxbrew/bin/brew shellenv)"

Reference