- Windows Sub-System for Linux (WSL)
- Working on Windows 10 with WSL
- Having a visually nice terminal through Windows Terminal (Preview)
zsh
as my main shell withoh-my-zsh
as well- Using Docker and Docker Compose directly from zsh
- Using VSCode (Insiders) directly from WSL 2
- 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
- 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 thewsl --install -d <Distribution Name>
command. - To see a list of available Linux distributions, enter
wsl --list --online
.
- In order to use the
- Enable WSL Optional Feature via
# 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>
# 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
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)
- Tool used to get URI: Microsoft Store - Generation Project.
- Scripts/Download-AppxFromStore.ps1 at a1163b97875ed075927438505808622614a9961f · MattiasC85/Scripts (github.com)
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
- From Linux/WSL Shell:
# update, upgrade, autoremove
sudo apt -y update && sudo apt -y upgrade && sudo apt -y autoremove
# initial installations
sudo apt install
#!/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
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.
- 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
gpg --full-generate-key
Read GitHub documentation about generating a new GPG key for more details.
#!/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'
[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
#!/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
#!/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)
- 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
#!/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
#!/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
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
#!/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
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
#!/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.
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
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
# unzip via tar
tar xvf <path/to/file.tar.gz>
# install unzip
sudo apt install unzip
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.
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
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:
now try to re-run scripts.
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: ✔️
Fix GPG keys also:
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)"
- What is Windows Subsystem for Linux | Microsoft Docs
- WSL Command Line Reference | Microsoft Docs
- sirredbeard/Awesome-WSL: Awesome list dedicated to Windows Subsystem for Linux (github.com)
- AptGet/Howto - Community Help Wiki (ubuntu.com)
- Get Ubuntu - Microsoft Store
- Announcing Ubuntu on Windows Community Preview – WSL 2 | Ubuntu