Install, Configure, and Use WSL on Windows 11
For me, WSL (Windows Subsystem for Linux) is the answer for working in both Linux and Windows environments. It works by running a Linux virtual machine within Windows. Although it's not perfect—nothing in the world is—WSL does a reasonably good job.
In this note, I will walk through the installation and configuration of WSL, and share some usages.
Introduction and Installation
According to the WSL documentation,
Windows Subsystem for Linux (WSL) lets developers run a GNU/Linux environment – including most command-line tools, utilities, and applications – directly on Windows, unmodified, without the overhead of a traditional virtual machine or dual-boot setup.
To install WSL, follow this official guide. It is as simple as running
a single command wsl --install
from PowerShell. However, if
any error occurs, please refer to the manual installation and see
whether some requirement is missing.
After the installation, one can use wsl
in PowerShell to (see this page for a full list of options)
- list available/installed Linux distributions;
- update WSL or check its status;
- shutdown or terminate running distributions;
- identify IP address;
- mount or unmount disks.
Clarification. In this note, I assume the WSL version is 2 and it runs a single Ubuntu distribution.
Configuration and Usage: Overview
Using WSL on Windows 11 is much like opening a terminal to connect to a separate Linux server, except that this Linux environment runs directly on the same machine.
To access the running Linux distribution in WSL, one can use Windows Terminal, a built-in terminal emulator to run shells on Windows. It is similar to the GNOME terminal on Ubuntu, as summarized by the following table.
Feature | Windows Terminal | GNOME Terminal |
---|---|---|
Platform | Windows | Linux |
Native Shells | Powershell, CMD, Bash (via WSL) | Bash, Zsh, Fish |
Profile-based customization | Yes | Yes |
Open source | Yes (MIT) | Yes (GPL) |
Here is the official documentation of Windows terminal.
Config: Windows Terminal
Below are my settings.
- Initial terminal size: 120 columns, 36 rows (measured in characters)
- Font name: Cascadia Code NF (a version of Cascadia that has Nerd Font symbols)
- Font size: 14
- Color scheme: Solarized light
- Intense text style: bold (not bright)
- Bell notification style: flash window (not audible)
The bash environment in WSL can be configured as in normal Linux distributions; my configurations are listed in Appendix: Bash Configuration.
Usage: Interoperability between Windows and Linux Commands
Windows and Linux tools and commands can be used interchangeably with WSL.
To run Linux tools from a Windows command line, prepend the bash command with wsl
:
wsl ls -la
To run Windows tools from WSL command line, append the tool name with .exe
:
explorer.exe .
See more examples and explanations on this page.
Usage: Work across Windows and Linux File Systems
Access Linux files from Windows or vice versa is generally slow. Nevertheless, it is still possible.
Windows files can be accessed by a Linux distribution under /mnt/c/
.
Linux files can be accessed by Windows under \\wsl$
(an address
recognizable for Windows File Explorer).
Usage: SSH into WSL from an External Machine
The goal is to configure WSL as a local server so that external machines can access WSL via SSH. Below is a summarized procedure; refer also to the official WSL documentation: Accessing network applications with WSL and How do I run an OpenSSH server? The note:2025-04-18::Remotely Develop a Python Project might also be helpful.
Step 1. Identify IP address. There are two machines involved: a Windows machine running WSL, and an external Ubuntu machine. However, there are three distinct IP addresses, as WSL itself has a virtual IP address. Here are example outputs from my machines.
# external Ubuntu machine dou-GramStyle # hostname 192.168.1.111 # hostname -I # Windows Powershell dou-Legion # hostname 192.168.1.104 # ipconfig # WSL terminal 172.27.71.86 # hostname -I
Before proceeding, ensure both machines are reachable on the local
network by trying ping
. There are 3 addresses, which means 6 possible
paths for communication. At this stage, 5 of these paths should be
working[1]. The path that will not work is from the external
machine to WSL, because the WSL address is only accessible from the
Windows host.
Step 2. Start SSH service on WSL. Install openssh-server
on WSL and
edit the the configuration
/ect/ssh/sshd_config
(this requires root permission). Look for similar
lines and change them to
# ... Port 2222 ListenAddress 0.0.0.0 PasswordAuthentication yes # ...
This tells SSH to use port 2222 and listen to any address. It also
enables the passward authentication. After saving the configuration,
start or restart the SSH device from WSL by sudo systemctl start
ssh.service
.
At this stage, it should be able to connect to WSL on the Windows
machine. Try running ssh wsl.localhost -p 2222
on PowerShell.
Step 3. Expose WSL address by port forwarding. To allow SSH from an external machine, I forward Windows port 2222 to WSL port 2222 and configure the firewall accordingly. This can be done from PowerShell by
# port forwarding netsh interface portproxy add v4tov4 listenaddress=0.0.0.0 listenport=2222 connectaddress=172.27.71.86 connectport=2222 # set up firewall netsh advfirewall firewall add rule name="Open Port 2222 for WSL2" dir=in action=allow protocol=TCP localport=2222
Once the port forwarding is correctly configured, I can directly SSH into WSL from my Ubuntu laptop
ssh dou-Legion.local -p 2222
Step 4 (Optional). Use SSH key authentication instead of passwoard
authentication. In step 2, the configuraiton file /ect/ssh/sshd_config
use password authentication for SSH login. It is possible to use SSH
keys for authentication; see Appendix: SSH Authentication via SSH
Keys.
Appendix: WSL 1 v.s. WSL 2
WSL 1 and WSL 2 are two different WSL architectures. WSL 2 architecture outperforms WSL 1 in several ways, with the exception of performance across OS file systems, which can be addressed by storing project files on the same operating system where the tools are installed.
Feature | WSL 1 | WSL 2 |
---|---|---|
Integration between Windows and Linux | ✅ | ✅ |
Fast boot times | ✅ | ✅ |
Small resource foot print compared to traditional Virtual Machines | ✅ | ✅ |
Runs with current versions of VMware and VirtualBox | ✅ | ✅ |
Managed VM | ❌ | ✅ |
Full Linux Kernel | ❌ | ✅ |
Full system call compatibility | ❌ | ✅ |
Performance across OS file systems | ✅ | ❌ |
See more comparisons in the official documentation.
Appendix: Bash Configuration
I am accustomed to my own evolving Bash profile and a collection of small tools. To ensure a consistent experience across Ubuntu, WSL, and remote servers, key elements include: 1) basic bash environment; 2) personal bash scripts; 3) standard tools like git, oh-my-posh, unison, emacs, and etc. For details, please refer to note:2025-08-06::Customize Bash on Ubuntu and Windows.
Appendix: SSH Authentication via SSH Keys
First, obtain a pair of SSH keys either by: 1) reusing existing
keys; 2) generating a new pair. Let dou-GramStyle:~/.ssh/id_ed25519
be
the private key and dou-GramStyle:~/.ssh/id_ed25519.pub
be the
associated public key.
Second, edit the ssh configuration file dou-GramStyle:~/.ssh/config
to
add the following lines
Host wsl HostName dou-Legion.local User dou Port 2222 IdentityFile ~/.ssh/id_ed25519
Third, save the public key to the server's authorized keys. This is
done by simply appending the content of
dou-GramStyle:~/.ssh/id_ed25519.pub
to
dou-Legion:~/.ssh/authorized_keys
(create if not existed).
Finally, disable password authentication on the server side. Edit the
ssh configuration file /etc/ssh/sshd_config
on the server. Look for
similar lines and change them to
# ... PubkeyAuthentication yes PasswordAuthentication no # ...
After restarting the ssh service, I could connect from the client by
simply typing ssh wsl
.
Footnotes:
If the Windows machine does not respond to ping, this could be an issue related network or firewall settings. First, please ensure the network profile is set to Private instead of Public. Second, try allow incoming ICMP requests using the Windows PowerShell command
netsh advfirewall firewall add rule name="Allow Ping" dir=in action=allow protocol=icmpv4