...
Code Block |
---|
C:\Users\gilbert>winget list|wsl grep Git Git Git.Git 2.48.1 winget GitHub Desktop GitHub.GitHubDesktop 3.4.17 winget |
WSL creates a very special Linux Virtual Machine running the Microsoft version of the Linux Kernel. Unlike other VMs, the Windows system is tightly connected to this Linux VM. Windows programs can directly access the Linux files, Linux has access to the Windows disks, Linux and Windows programs can share the same network adapters, and you can combine Linux and Windows programs on the same command line.
If you want the full Linux Gnome Desktop experience, create a normal Linux VM with Hyper-V. WSL is command line only, but you can install individual Linux GUI programs into WSL and when you run them an application window pops up on the Windows desktop:
...
The Microsoft Linux Kernel runs a special non-Docker container system. You can install one or more Linux “distributions” (Ubuntu, Debian, SUSE, etc.) each into their own container under the Kernel. Unlike Docker, this special container system lets the distributions run systemd background services and shares resources like network adapters. Each distribution has its own isolated file system, processes, and libraries.
The default and probably best adapted distribution is Ubuntu (24.04 LTS). Ubuntu has supported WSL since the earliest version, installs with systemd and snap enabled, and provides the widest library of programs that you can install and run using the apt package manager.
If you are going to run a sequence of Linux commands, then typing the command “wsl” with no arguments converts the Windows command line into a Linux bash session (like running ssh to a Linux machine on the network). Microsoft also provides a bash.exe command that does the same thing.
There is no way to translate Windows file access control to Linux file permissions. The WSL environment is, therefore, private to each Windows user. If two users are logged into the same Windows machine, each has their own personal copy of WSL Ubuntu. The user has implicit full (root) control over his own WSL system and files. Anything in WSL cannot be directly shared with another user. However, if a WSL service connects to the network as port 8080, then other users on the same machine can connect to localhost:8080 and access the service over what appears to be “the network”.
On Windows, the Linux file system in your Ubuntu distribution is referenced by the Windows UNC name of \\wsl$\ubuntu.
is a Microsoft product. It adds limited individual Linux program execution to a Windows operating system, but Windows remains completely in charge and the user mostly runs Windows applications from the Windows desktop. If you want to add a full Linux operating system to your Windows laptop, then use Hyper-V to create a virtual machine. Then you have the full experience of installing, configuring, and administering Linux and you get the user interface of a full Linux desktop like Gnome.
The first version, called WSL 1, emulated the Linux application program services on a pure Windows system. That provided poor performance and there were some Linux features that could not be emulated. The current version, called WSL 2, runs a Microsoft version of the Linux kernel in a virtual machine, then installs various “distributions” of Linux (Ubuntu, Debian, Kali, Fedora, RHEL) on top of that Kernel. The trick is that Microsoft has added logic to both the Windows Kernel and the Linux Kernel so that they communicate to each other to create a seamless user experience.
You can simply install WSL on your Windows system and use it casually. There is other documentation for an end user. The purpose of this paper is to describe how WSL works so that a slightly more advanced user, like a developer, can understand how to make more advanced use of the service.
Therefore, we will start with a high-level overview of how WSL works as a whole, then drill down into individual components to understand what will work, what won’t work, and how to get it to do what you want.
A Short History
The first version of Windows NT 3.1 somewhere around 1993 had a Posix Subsystem that provided a stipped down Unix compatible application programming interface. Over time, that was expanded to a Unix Subsystem with a more complete API, and that was expanded to WSL 1. For any of these to work at all, the Windows Kernel and File System has always had support for Unix behavior as well as Windows behavior. For example, the Windows file system has always been able to create two different files in the same directory whose names differ only by case, but case-insensitive Windows did not create or support such files.
Ultimately Microsoft had to admit that emulation didn’t work. To get real Linux compatibility, you needed the real Linux Kernel, and to maintain sanity you needed separate file systems, one pure Windows and one pure Linux, but then connect them to each other as if there was a network file share between the two.
When and How do you Switch?
If you have a Linux system on your network, whether it runs on a real computer or a VM, you can connect to it and run commands with ssh and share files over the network. In both cases, however, you need an account on both systems and must authenticate to the Linux account when you connect.
WSL is designed to be a single system. You login to Windows once and that is the only authentication you need. Linux requires you to create a user name with a user id number, but once that is created the behavior is a single identity that extends across systems.
If you are running Windows Command Line (cmd.exe) you can type “ssh” to start Bash on a remote Linux system. Until you type “exit”, the commands you enter into your Windows cmd.exe window are sent to Linux and execute remotely. By typing the ssh command in Bash you can open a session to Windows and the commands you enter into your Linx “term” window will run remotely on Windows.
In WSL, you can switch between Windows and Linux based on the type of program that the system is going to run next. This is literally true in the Microsoft Linux Kernel, which has been modified so that when Linux is about to run a program from its disk, and the program has an extension of *.exe and is a Windows executable, then the Linux Kernel realizes that the program has to run in Windows and automatically begins the process of communicating with the Windows Kernel to switch the context back to Windows execution. For this to work, the Linux current directory has to be preserved and become the Windows current directory. Microsoft also converts the Linux Environment variables to Windows.
Linux programs do not have a special extension. We could imagine a future version of Windows where the Kernel is capable of identifying a file as a Linux executable, but for now you must explicitly add “wsl” (wsl.exe) in front of any Linux command that you want to run from the Windows environment. That program switches the execution environment from Windows to Linux while again preserving the current directory and mapping the environment variables.
A command line entered in either environment can have a string of mixed Windows and Linux commands separated by the pipe “|” operation. When this happens, WSL in either environment arranges for the standard output of the program running on the left side of “|” to be shipped through the WSL connection between the two environments and then fed as standard input to the program on the right side of “|”.
Authentication, Security, Access
There is no reasonable way to design a mapping between the complex Windows file permissions system and the Linux owner/group/everyone permissions model. As explained above, the WSL security model is that you logged into Windows with your Windows Userid and that must become your only security context and decide your access to everything.
To accomplish this, the Linux “system” created by Windows is an internal component private to your Windows login. Each Windows user gets a personal copy of Linux programs and files. You cannot share it with someone else, and no other user can connect to it with SSH. You can run a Web application in WSL that provides a service on a port, and another user can run a client program that connects to it, but that is the only type of cross user interaction permitted.
The Windows user is effectively the administrator of his own Linux instance, with “root” access to its file system. The WSL Linux system as a whole accesses Windows files as the currently logged in Windows user that owns it.
The WSL Linux Kernel is a Windows Component
Microsoft distributes and maintains the WSL Linux Kernel. They can replace it on Patch Tuesday as part of monthly maintenance. They can upgrade it with new releases. This does not affect your WSL instance. All your programs and packages continue to run as before.
You get to choose one or more Linux “distributions” to use when creating a WSL instance. If you choose to install Ubuntu 24.04 on a physical computer or VM, you download an ISO file or USB drive image that you boot to run the installer, and it contains a Linux Kernel that it installs on the destination machine. A WSL Linux “distribution” contains all the same files, programs, and libraries, but it does not have its own Kernel. Also, a WSL Linux “distribution” is a tar file backup of the file system that is restored by Windows to a virtual hard disk VHDX file rather than a bootable DVD or USB image.
It is a Container, but not the type you are used to
Unix has always had the concept of generic “containers”. When any Unix program creates a child process, it can restrict the environment of the child so that it cannot see certain directories and devices, or where the parent program substitutes alternatives for standard well known system devices.
Docker turned this feature into a very powerful system for running applications, but the Docker container is a specific use of the general idea which Docker optimized to run a single application in the smallest, most efficient, and easiest to maintain non-interactive background service. While building, testing, and debugging an application for Docker, a developer could run a container in interactive mode with the equivalent of ssh to bash.
In the early days of WSL 1 and the original WSL 2, a WSL Linux distribution was limited to “single user mode” without background services, which is essentially the same behavior as a Docker container. However, WSL is inherently interactive, and over time the WSL Linux distributions have become versions of the full operating system with background services (running under “systemd”) and pretty much everything in the “server” distributions of Linux (everything but a desktop like Gnome).
You can do all that in a container, it is just not a Docker container anymore. Running a WSL distribution in a specialized container management system solves two problems:
Container images always contained a copy of all the Linux system programs, files, libraries, packages, and configuration distributed as tar files without a copy of the Kernel. That approach was exactly what WSL needs.
The tight coupling between the WSL Microsoft Linux Kernel and the Windows Kernel could be most easily implemented if there was only one WSL Linux VM with one Kernel. If that one Kernel then created a container system and ran Linux distribution images in isolated containers, it could create the required separation between different distributions run by different Windows users while maintaining the simplicity of a single VM.
What about Linux GUI apps?
Unix originally ran on large computers. Users sat at desktop terminals and connected to the Unix machine over phone lines. A terminal provided a screen and keyboard and just enough electronics to send keystrokes over the phone to the computer and send characters back from the computer and write them to the screen.
When people wanted graphical applications, a more powerful terminal was created and a communications protocol was developed named “X”.
The PC was created, and over time it replaced the X terminal, but there were lots of programs written to what was then the X11 API. As Unix migrated to the PC, the simplest solution was to preserve the X11 interface and add to Linux separate logic to manage the screen, keyboard, and mouse with code that emulated an X11 terminal, get rid of the phone line or network, and internally connect the emulated terminal to the existing applications. This persisted for a surprisingly long time in an era where Windows was running DirectX12 and video cards had a GPU, gigabytes of RAM, and various computer APIs.
There were lots of programs that ran on Windows and emulated an X11 terminal.
Slowly Linux has developed an alternative to X11 named Wayland, which makes more sense when the keyboard, mouse, and display adapter are directly connected to the computer on which Linux is running. WSL added a version of the Wayland Compositor component running in Windows while the rest of Wayland continues to run in the Linux Kernel. This allows applications running in WSL Linux to “open a window on the screen” and have that window open on the Windows desktop.
Integrated File Systems
Linux has always been able to share and use shared files with Windows over the network (Samba, CIFS). However, directories have to be explicitly shared, and the client has to provide credentials. Security is a constant issue.
In WSL there is only one user. The programs you run in Windows or Linux are your programs, and you have every right to access your files in either the Windows or Linux file systems. Therefore, WSL exposes all your Linux files to your user session on Windows. Linux gains access to Windows files though your Windows login and inherits your permission to the subset of Windows files you can access.
The Windows File Manager has a “Linux” section that displays your WSL Linux instances
...
And if you select one you see all the Linux directories:
...
But if you want to access them through a path expression, there is a UNC name of the form \\wsl$\ubuntu.
Code Block |
---|
C:\Users\gilbert>dir \\wsl$\Ubuntu\ Directory of \\wsl$\Ubuntu 03/31/2024 04:00 AM <DIR> sbin.usr-is-merged 02/11/2025 07:59 PM 2,424,984 init 09/27/2024 03:13 PM <DIR> srv 11/23/2024 08:12 PM <DIR> mnt 03/07/2025 11:42 AM <DIR> proc 03/07/2025 11:42 AM <DIR> dev |
...
Code Block |
---|
ls -ltr /mnt
total 0
drwxrwxrwx 1 gilbert gilbert 4096 Mar 7 11:16 d
drwxrwxrwx 1 gilbert gilbert 4096 Mar 7 11:16 c
drwxrwxrwx 1 gilbert gilbert 4096 Mar 7 11:16 e
drwxrwxrwt 2 root root 60 Mar 7 11:48 wsl
drwxrwxrwt 7 root root 300 Mar 7 11:48 wslg |
While /home/username is your Linux home directory, when you run a Linux program from Windows then the program starts in the same current directory that Windows had, expressed through the mapping:
Code Block |
---|
C:\Users\gilbert>wsl
gilbert@MWPFxxxxx:/mnt/c/Users/gilbert$ |
When you go from Windows to Linux, your Windows Environment variables are merged with Linux environment variables.
In Linux, if you type a command that turns out to be a *.exe program, the Microsoft Linux Kernel handles the transition from Linux back to Windows. At this time there is no way for Windows to automatically recognize a Linux program, so you have to run “wsl <programname>”. However, you can create a programname.bat file somewhere in your Windows path. For example, grep.bat could contain:
wsl grep %*
...
Mar 7 11:48 wslg |
Here you can see the C, D, and E disk letters. Based on the rule that when you switch between systems, you get the same current directory after the switch, while Linux gives you the usual $HOME of /home/userid, if you enter Linux by tying the wsl.exe or bash.exe command, you end up with the previous Windows current directory expressed in its WSL path form:
Code Block |
---|
C:\Users\gilbert>wsl
gilbert@MWPFxxxxx:/mnt/c/Users/gilbert$ |
Here the command prompt shows that the current directory was C:\Users\gilbert, and when you get to bash in Linux you are in the same directory, but the path is now expressed as starting in /mnt.
Installation
You can install WSL and the distribution from the Windows Store in Windows 11. However, there is no Store in Windows Server 2025, so you might as well get used to the command line.
Windows 11 Home Edition is not licensed to allow use of the full Hyper-V. There is a limited function “no configuration” version of Hyper-V that gets installed to run WSL.
If WSL is not installed, just run the Windows commandrun an elevated (Run as administrator) command prompt and enter
wsl --install
This command installs the minimal Hyper-V feature, then downloads and installs the Microsoft Linux Kernel, and then finally downloads and installs the default Ubuntu distribution. You typically then have to This requires a reboot to enable everything.
To list the other available distributions (without using Store), type the Windows command
wsl --list --online
...
complete the installation. When you run wsl for the first time, the Ubuntu system will go through a first time initialization asking you to enter the userid and password that will administer the system.
WSL Implementation
Network Protocol
Bell Labs created Unix when computers were big expensive machines the smallest computer was still expensive and shared by multiple users. One people switched to using networks of smaller computers, they
As smaller, less expensive machines became common and were connected to each other over high speed networks, the people who developed Unix started work on a successor project to Unix with a codname of “Plan 9”. The idea was to make a network of PCs look like a single system with a lot of users. Files on different computers create a new OS specifically designed for that type of hardware. They named the project after what is widely regarded as the Worst, Cheesiest Movie Ever Made, a film titled “Plan 9 From Outer Space”. The project never completed, and the system was never released.
However, their first problem was to imagine a set of services and a network protocol that would more closely couple small computers to each other so they would appear to be one big file system, and programs and servers running on different machines would look like they were all running in one operating system. To make this work, they developed a very powerful network-based disk sharing and program to program communication protocol named “9P”.
Microsoft adopted 9P as a way to combine the Windows OS (disks, files, programs) with a Linux OS so that the combination of two systems looked to the user like a single tightly integrated system. However, the Microsoft adaptation of 9P runs between a logged in Windows user and the WSL Linux VM started by that logged in user.
While Windows and Linux assume that everything is private by default and a user has to explicitly share disks or directories with the network, the 9P model is that everything is shared by default and something is private by setting permissions. This aligns with the view that while you are logged into Windows and running WSL, your Windows programs have full access to everything on your personal copy of a WSL distribution, and WSL programs you run have access to anything on Windows that you (the currently logged in user under which WSL is running) have access to.
WSL originally ran in single user mode (like a Docker container). Then Microsoft added support for systemd by adding an option in the /etc/wsl.conf file in the WSL distribution file system. Ubuntu defaulted to enabling systemd after 23.10.
WSL has some complicated rules for networking that require their own section.
The Distros
Microsoft provides the Hyper-V feature and the Linux Kernel.
Various suppliers provide WSL Distributions in the form of a tar file containing a file system. While the “wsl --install <distroname>” command will download and install a distro from the Microsoft library, you can get a tar file from some other source and create a distro from it.
The non-Docker container that runs a distro stores its files in a Hyper-V virtual disk (*.vhdx) file somewhere in the C:\windows directory. Changes made while the distro runs are written to the virtual disk and persist (whereas Docker containers do not persist changes to their file systems).
Generally, the distro named “Ubuntu” is the same version as the most recent explicit named version (“Ubuntu-24.04” as this is written). You can create two separate versions of the latest version of Ubuntu distinguished by these two names. Each will have their own distinct files on separate virtual disks. If you need a third instance of Ubuntu, you need to “wsl --export” a tar file with a file system and then “wsl --import” the tar file you just generated, giving it a new distro name.
If you are inclined to create a distro from a Beta version of Ubuntu, they keep compressed tar files in a public Web site called https://cloud-images.ubuntu.com/releases/. Remember to unzip the file because “wsl --import” takes a tar and not a tar.gz file.
One distro is designated the Default. It is the distro you run when you type the “wsl” command without a distro name.
WSL Networking
This is a subject that is constantly being changed by Microsoft, but there are a few basic ideas that remain constant.
First, the “localhost” address of 127.0.0.1 behaves like a network adapter but it has nothing to do with the network. In both the Windows and Linux Kernels, localhost is implemented with a dummy device and a special device driver so that a client program can talk to a server program on the same computer without data ever going to any network.
There is support in both the Windows and Linux Kernel drivers for the dummy localhost devices that they know about each other and communicate using Hyper-V to create what amounts to a single coordinated localhost device across both systems. If two programs running in Windows and WSL both try to act as servers on port 8080, then one of them will get the port and the other will be told that the port is in use by someone else. Client programs on either Windows or WSL can then connect to localhost:8080 and talk to whichever server got the port. Data will be transferred as needed between the localhost drivers in the Windows Kernel and the Linux Kernel.
Experimentally (at the time this is being written) this behavior can also be extended to all the real network adapters in the Windows system. If network “mirroring” is enabled, the Linux Kernel creates a dummy Linux network adapter for every real Windows network adapter. It is experimental because Windows has to be in control, so Linux cannot attempt to reconfigure the network adapter to have different addressing or behavior. Client programs on either Windows or Linux can use an adapter to access servers on the real network, and server programs on Windows or Linux get a “first wins” resolution when they try to bind to an IP address and specific port number.
The default WSL network behavior is that the Linux Kernel creates one virtual network adapter that is connected to Windows, and Windows provides a NAT gateway through which client Linux programs in any Linux distribution can access the Internet. Linux server programs should bind to localhost as described abovesystem so each computer would lose its individual identity and just become part of overall “hive mind”. The protocol was called 9P. When Microsoft was looking for a way to tie the Windows logged on use to a WSL Linux container as if it were a single integrated system, they decided that 9P was a good starting point. It went far beyond shared files and solved the problem of triggering remote execution, propagating environment variables to another system, and piping the output of one program to the standard input of another program running on another machine.
Windows Home Edition
Windows Home Edition is not licensed to run Hyper-V, but it does support WSL. When Microsoft decided to move from WSL 1 (Emulation) to WSL 2 (Linux Kernel VM), they created a version of Hyper-V that had no user interface, no configuration options, and could create only specific virtual machines defined by Microsoft.
When you enable WSL, if you do not already have Hyper-V enabled on your computer then Windows will install this limited use version of it automatically. No matter which version of Hyper-V you get, you have to reboot to complete the installation.
The Distros
WSL 1 had already defined the format of a tar backup of a Linux file system that could be restored to create a WSL “distro”. However, in WSL 1 this tar file was restored to a hidden subdirectory of one of the Windows system directories on your NTFS C:\ drive. This hidden directory was flagged to use the Unix-compatible option that was part of the original NTFS design but was almost never used, where file names were case sensitive and text files had Unix line end characters.
WSL 2 supported the exact same distro tar file, but restored it to a VHDX virtual disk file that could be formatted with a real Linux file system.
Microsoft provides a library of WSL distros supplied by partners. Ubuntu (currently 24.04) is the default and will be installed when you enable WSL unless you actively prevent it with the --no-distribution option. You can list other options with the command:
wsl --install --online
You can choose a distribution to install with
wsl --install <distroname>
WSL distributions can also be installed with Windows Store, but the command line installation works on Windows Server, where Store is not available.
This easy command interface allows you to create one WSL distro container instance of any named distribution. To create a second instance of the same distribution (with different files and a selection of different packages), you have to start with a first installed distro, then run the command
wsl --export <distro> <tar-file-pathname>
to create a tar file backup of the distro. Then you can clone it to a second named WSL container with the command
wsl --import <newdistroname> <location> <tar-file-pathname>
where <location> is the Windows disk file directory under which a new directory is created with the newdistroname under which all the new distro files are stored.
One distro is designated the Default. It is the distro you run when you type the “wsl” command without a distro name.
WSL Networking
This is a subject that is constantly being changed by Microsoft, but there are a few basic ideas that remain constant.
Concept: There is one “localhost” shared by Windows and WSL
Actually, localhost (address 127.0.0.1) is a device driver in both the Windows and Linux Kernel. It is always a virtual network adapter with no real network and no physical device. It allows two programs on the same computer to talk to each other as if they were talking through a network.
The Localhost device drivers in Windows and Microsoft Linux have been modified to know about each other and the Hyper-V system that connects them. They coordinate their actions to behave as if they were a single entity. When programs bind to port numbers, the two drivers synchronize this operation so that only one program on either system owns the port. When data is transferred between clients and servers, Hyper-V is called to move the data when one program is on Windows and the other is in WSL.
It was previously noted that multiple distributions running in containers on the WSL Kernel share the Linux localhost device. As a result, localhost can be used to communicate between two programs whether they are running in the same system, one is in Windows and one is in a WSL distro, or each is in a different Linux distro.
Fact: Distro Containers see WSL VM Virtual Network Adapters
There is limited Microsoft documentation.
Docker hides all real devices from its containers, but the WSL container system exposes not just Localhost, but all the virtual network adapters attached to the WSL Linux VM.
However, you cannot control the creation of the WSL Linux VM, nor can you see it in Hyper-V Manager, nor can you change it. The standard behavior is that WSL creates one virtual network adapter (eth0) connected to a virtual network adapter on the host Windows system called “vEthernet (WSL (Hyper-V firewall))” which provides a gateway function with NAT (network address translation) and DNS. Using this each WSL distro gets access to the Internet though the same path as applications running on the host.
Alternately, you can enable networkingMode=mirrored. This is not well explained by Microsoft, but it appears to be an approach that extends the behavior of the Localhost virtual device to all of the real network adapters on the Windows system. The device drivers in Windows and Linux synchronize port assignment, and Hyper-V moves data between the Linux virtual device and the Windows physical device as needed.
Because distro containers share virtual network adapters on the WSL Linux Kernel, they share access to the real host network adapters as well.