WSL Documentation

Windows Subsystem for Linux

33,381 stars C++ C++ 1 file Β· ~6,773 tokens
RAW Doc

Docker & Self-Hosted Deployment Verified OCI

Deploy WSL on any server, homelab, or cloud container platform.

1-Click Terminal Command
bash (docker run)
docker run -d --name wsl --restart always microsoft/wsl:latest

1. Project Overview & Quickstart (microsoft/WSL)

File: README.md

Welcome to the Windows Subsystem for Linux (WSL) repository

Learn more about WSL | Downloads & Release notes | Contributing to WSL

About

Windows Subsystem for Linux (WSL) is a powerful way for you to run your Linux command-line tools, utilities and applications, all unmodified and directly on Windows without the overhead of a traditional virtual machine or dual boot setup.

You can install WSL right away by running this command inside of your Windows command line:

powershell
wsl --install

You can learn more about best practices for setup, overviews of WSL and more at our WSL documentation page.

WSL also has related open source repositories:

Contributing

This project welcomes contributions of all types, including coding features / bug fixes, documentation fixes, design proposals and more.

We ask that before you start working on a contribution, please read our Contributor's Guide.

For guidance on developing for WSL, please read the developer docs for instructions on how to build WSL from source and details on its architecture.

Code of Conduct

This project has adopted the Microsoft Open Source Code of Conduct

Trademarks

This project may contain trademarks or logos for projects, products, or services. Authorized use of Microsoft trademarks or logos is subject to and must follow Microsoft’s Trademark & Brand Guidelines. Use of Microsoft trademarks or logos in modified versions of this project must not cause confusion or imply Microsoft sponsorship. Any use of third-party trademarks or logos are subject to those third-party’s policies.

Privacy and telemetry

The application logs basic diagnostic data (telemetry). For more information on privacy and what we collect, see our data and privacy documentation.

The software may collect information about you and your use of the software and send it to Microsoft. Microsoft may use this information to provide services and improve our products and services. You may turn off the telemetry as described in the repository. There are also some features in the software that may enable you and Microsoft to collect data from users of your applications. If you use these features, you must comply with applicable law, including providing appropriate notices to users of your applications together with a copy of Microsoft’s privacy statement. Our privacy statement is located at https://go.microsoft.com/fwlink/?LinkID=824704. You can learn more about data collection and use in the help documentation and our privacy statement. Your use of the software operates as your consent to these practices.


File: doc/docs/technical-documentation/boot-process.md

The WSL2 boot process

This page describes the steps in the WSL2 process, from the user invoking wsl.exe to the user's Linux shell (bash in this example), in the WSL2 distribution.

Overview

The below diagram shows the sequence of events to start bash within a WSL2 distribution. See WSL architecture for details about what each process does.

mermaid
sequenceDiagram
    wsl.exe->>wslservice.exe: CreateInstance(<distro>)
    wslservice.exe->>wsl.exe: S_OK
    wsl.exe->>wslservice.exe: CreateLxProcess(<distro>, <command line>, <env>, ...)
    create participant mini_init
    wslservice.exe->>mini_init: LxMiniInitMessageEarlyConfig
    create participant gns
    mini_init-->>gns: fork(), exec("/gns")
    wslservice.exe->>gns: LxGnsMessageInterfaceConfiguration
    gns->>wslservice.exe: LxGnsMessageResult
    wslservice.exe->>mini_init: LxMiniInitMessageInitialConfig
    wslservice.exe->>mini_init: LxMiniInitMessageLaunchInit
    create participant init
    mini_init-->>init: fork(), exec("/init")
    init->>wslservice.exe: LxMiniInitMessageCreateInstanceResult
    wslservice.exe->>init: LxInitMessageCreateSession
    create participant session leader
    init-->>session leader: fork()
    session leader->>wslservice.exe: LxInitMessageCreateSessionResponse
    wslservice.exe->>session leader: InitCreateProcessUtilityVm
    create participant relay
    session leader-->>relay: fork()
    relay->>wslservice.exe: LxMessageResultUint32 (hvsocket connect port)
    wslservice.exe->>relay: connect hvsockets for STDIN, STDOUT, STDERR
    create participant bash
    relay-->>bash: fork(), exec("/bin/bash")
    relay<<-->>bash: relay STDIN, STDOUT, STDERR
    wslservice.exe-->>wsl.exe: S_OK + hvsockets for STDIN, STDOUT, STDERR
    wsl.exe<<->>relay: Relay STDIN, STDOUT, STDERR
    destroy bash
    relay-->>bash: waitpid()
    relay->>wsl.exe: LxInitMessageExitStatus (process exit code)

CreateInstance()

When wslservice.exe receives the CreateInstance() call via COM, it will:

  1. Identify which distribution the user wants to create. This is done by looking up the DistributionRegistration (see src/windows/service/exe/DistributionRegistration.cpp) in the Windows registry, matching either on the distribution ID, or using the default if none is provided.

  2. Based on the type of distribution (WSL1 or WSL2), either create a WSL1 instance, or start up a WSL2 virtual machine.

  3. Associate the newly creating distribution to the calling process (see src/windows/service/exe/Lifetime.cpp)

Starting the WSL2 virtual machine

To start a WSL2 distribution, wslservice.exe needs a virtual machine. If the virtual machine isn't already running, it will be created as part of the CreateInstance() call.

The WSL2 virtual machine is created via the Host Compute System (HCS) service (see src/windows/service/exe/WslCoreVm.cpp).

To create a new virtual machine, wslservice.exe generates a JSON string, which describes the virtual machine configuration. This JSON is then passed to HcsCreateComputeSystem() to create a new virtual machine.

See src/windows/common/hcs_schema.h for more details on the HCS JSON schema.

Part of the JSON configuration includes:

  • The kernel: WSL will use its built-in kernel, usually installed in C:\Program Files\WSL\tools\kernel, or a custom kernel if overridden via .wslconfig
  • The initramfs: WSL uses its own initramfs (usually installed in C:\Program Files\WSL\tools\initrd.img). It's an image that only contains the mini_init binary
  • The resources accessible to the virtual machine such as CPU, RAM, GPU, etc

When started, the virtual machine will boot into the provided kernel, and then execute mini_init.

The Linux boot process

mini_init is the process that performs usermode initialization inside the virtual machine. After performing various configurations, mini_init receives a LxMiniInitMessageEarlyConfig message from the wslservice.exe which contains the following information:

  • Identifiers for the system VHD, swap VHD and kernel modules VHD if any
  • The machine's hostname
  • The configured memory reclaim mode and page reporting order

mini_init then creates the gns process, which is responsible for networking configuration and then receives a LxMiniInitMessageInitialConfig message, which contains:

  • An entropy buffer, to seed the virtual machine's entropy
  • Information about the GPU drivers shares to mount, if any
  • Whether wslg is enabled

After applying all the configuration requested by wslservice.exe, the virtual machine is ready to start Linux distributions.

Starting a Linux distribution

To start a new distribution, wslservice.exe sends a LxMiniInitMessageLaunchInit message to mini_init, which then mounts the distribution vhd and starts init. See init for more details on WSL2 distributions configuration.

Once running, wslservice.exe can then send a LxInitMessageCreateSession message to start a new session leader inside that distribution, which can be used to launch Linux processes

Relaying the Linux process's input and output to Windows

Once the user's Linux process has been created, wslservice.exe can return from CreateLxProcess() back to wsl.exe. In the case of WSL2, wsl.exe receives the following HANDLES:

  • STDIN
  • STDOUT
  • STDERR
  • Control channel
  • Interop channel

The STDIN, STDOUT and STDERR handles are used to relay input and output from the Linux process to the Windows terminal. Depending on the type of handle (terminal, pipe, file, ...), wsl.exe will apply different relaying logics (see src/windows/common/relay.cpp) to achieve the best compatibility between Windows & Linux.

The Control channel is used to notify the Linux process of a change in the terminal (for instance when wsl.exe's terminal window is resized) so these changes can be applied to the Linux process as well.

The Interop channel has two usages:

  • Create Windows processes from Linux (see interop)
  • Notify wsl.exe when the Linux process has exited (see LxInitMessageExitStatus)

Once the Linux process has exited, wsl.exe flushes all remaining IO, and exits with the same exit code as the Linux process.

If wsl.exe is terminated before the Linux process exits, wslhost.exe will take over the Interop channel and continue to handle requests to execute Windows processes.


File: doc/docs/technical-documentation/drvfs.md

Accessing Windows drives from Linux

WSL offers mountpoints to access Windows drives from Linux. These mountpoints are mounted under /mnt by default, and point to the root of Windows drives.

Elevated vs non-elevated mountpoints

Within a distribution, WSL separates between Linux processes that have been created from an elevated (as in administrator level) and from a non-elevated (user level) context.

This is done by having two separate mount namespaces within the distribution. One of them offers an elevated access to Windows drives, and the other offers a non-elevated access to Windows drives.

When a Linux process is created, wslservice.exe determines its elevation status, and then tells init to create the process in the appropriate mount namespace.

Mounting a Windows drive

*Note: This section only applies to WSL2 distributions. *

When a session leader is created, wslservice.exe starts a plan9 file server. This file server can be connected to from the WSL2 virtual machine to mount Windows drives.

When the WSL distribution is created, wslservice.exe uses the LX_INIT_CONFIGURATION_INFORMATION message to indicate whether the process that created the distribution is elevated or not. Based on this, init will mount either the elevated, or un-elevated version of the plan9 server.

Later when the first command is created in the namespace that hasn't been mounted yet, (either elevated, or non-elevated), wslservice.exe sends a LxInitMessageRemountDrvfs to init, which tells init to mount the other namespace.

See: src/windows/service/exe/WslCoreInstance.cpp and src/linux/drvfs.cpp.

Mounting a drive from Linux

As long as the Windows plan9 server is running, drives can be mounted simply by calling mount. For instance mounting the C: drive manually can be done via:

text
mount -t drvfs C: /tmp/my-mount-point

Internally, this is handled by /usr/sbin/mount.drvfs, which is a symlink to /init. When /init starts, it looks at argv[0] to determine which entrypoint to run. If argv[0] is mount.drvfs, then /init runs the mount.drvfs entrypoint (see MountDrvfsEntry() in src/linux/init/drvfs.cpp).

Depending on the distribution configuration, mount.drvfs will either mount the drive as drvfs (WSL1), or plan9, virtio-plan9 or virtiofs (WSL), depending on .wslconfig.


File: doc/docs/technical-documentation/gns.md

GNS

gns is a process created by mini_init. Its job is to configure networking within the WSL2 virtual machine.

Networking configuration

Networking settings are shared by all WSL2 distributions. While WSL2 is running, gns maintains an hvsocket channel to wslservice.exe, which is used to send various networking related configurations such as:

  • Interface IP configuration
  • Routing table entries
  • DNS configuration
  • MTU size configuration

When DNS tunneling is enabled, gns is also responsible for replying to DNS requests.

See src/linux/init/GnsEngine.cpp and src/windows/service/exe/GnsChannel.cpp


File: doc/docs/technical-documentation/index.md

WSL Overview

WSL is comprised of a set of executables, APIs and protocols. This page offers an overview of the different components, and how they're connected.
Click on any component to get more details.

mermaid
%%{ init: {
    'flowchart': { 'curve': 'stepBefore' },
    'theme': 'neutral'
    }
}%%
graph
  subgraph Windows["**Windows**"]
      C:\Windows\System32\wsl.exe["C:\Windows\System32\wsl.exe"]---|"CreateProcess()"|wsl.exe;
      wsl.exe[[wsl.exe](wsl.exe)]---|COM|wslservice.exe;
      wslg.exe[[wslg.exe](wslg.exe)]---|COM|wslservice.exe;
      wslconfig.exe[[wslconfig.exe](wslconfig.exe)]---|COM|wslservice.exe;
      wslapi.dll[[wslapi.dll](https://learn.microsoft.com/windows/win32/api/wslapi/)]---|COM|wslservice.exe;
      id[debian.exe, ubuntu.exe, ]---|"LoadLibrary()"|wslapi.dll;
      wslservice.exe[[wslservice.exe](wslservice.exe)]---|"CreateProcessAsUser()"|wslrelay.exe[[wslrelay.exe](wslrelay.exe)];
      wslservice.exe---|"CreateProcessAsUser()"|wslhost.exe[[wslhost.exe](wslhost.exe)];
      fs["Windows filesystem (//wsl.localhost)"]
  end
  
  wslservice.exe -----|hvsocket| mini_init
  wslservice.exe -----|hvsocket| gns
  fs---|hvsocket|plan9

  wsl.exe---|hvsocket|relay
  
  subgraph Linux["**Linux**"]
      mini_init[[mini_init](mini_init)]---|"exec()"|gns[[gns](gns)]
      mini_init---|"exec()"|init[[init](init)];
      mini_init---|"exec()"|localhost[[localhost](localhost)];
      
      subgraph "Linux Distribution"["**Linux Distribution**"]

          init[[init](init)]---|"exec()"|plan9[[plan9](plan9)];
          init---|"exec()"|sid[session leader];
          sid[[session leader](session-leader)]---|"exec()"|relay
          relay[[relay](relay)]---|"exec()"|cid["User command (bash, curl)"]
      end

  end

File: doc/docs/technical-documentation/init.md

Init

Init is top level process of a WSL distribution. For WSL1 distributions, it is launched by wslservice (see src/windows/service/LxssInstance.cpp) and for WSL2 distributions, it is launched by mini_init.

WSL2 specific distributions startup

Each WSL2 distributions runs in a separate mount, pid and UTS namespace. This allows distributions to run in parallel, without "seeing" each other.

When a WSL2 distribution starts, mini_init:

  • Mounts the distribution VHD
  • Clones into a child namespace
  • Chroots in the VHD mountpoint
  • Executes init (see the LxMiniInitMessageLaunchInit message).

While each distribution runs in its own mount namespace, the /mnt/wsl mountpoint is shared between all distributions.

Distribution initialization

Once started, the init process performs various initialization tasks such as:

  • Mounting /proc, /sys and /dev
  • Configuring cgroups
  • Registering the binfmt interpreter (see interop)
  • Parsing /etc/wsl.conf
  • Starting systemd (see systemd)
  • Mounting drvfs drives (See drvfs)
  • Configuring wslg (see wslg)

Running the distribution

Once ready, init establishes either an lxbus (WSL1) or an hvsocket (WSL2) connection to wslservice. This channel is used to transmit various commands to init (see src/shared/inc/lxinitshared.h), such as:

  • LxInitMessageInitialize: Configure the distribution
  • LxInitMessageCreateSession: Create a new session leader. See session leader
  • LxInitMessageTerminateInstance: Terminate the distribution

File: doc/docs/technical-documentation/interop.md

Running Windows executables from Linux

The ability to launch Windows processes from Linux is controlled by 2 different levels of settings:

  • The HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\LxssManager\DistributionFlags registry value, which controls the settings for all Windows users (setting the lowest significance bit disables interop)
  • The [interop] section in /etc/wsl.conf, which controls the setting for a given WSL distribution.

binfmt interpreters for Windows executables

To allow Windows process creation from Linux, WSL registers a binfmt interpreter, which tells the kernel to execute an arbitrary command when a specific type of executable is launched via exec*() system calls.

To perform the registration, WSL writes to /proc/sys/fs/binfmt_misc and creates a WSLInterop entry, which points to /init. For WSL1 registration, the entry is written by init for each distribution, for WSL2 mini_init registers the binfmt interpreter at the virtual machine level.

Note: The /init executable is the entrypoint for different WSL processes (init, plan9, localhost, etc). This executable looks at argv[0] to determine which logic to run. In the case of interop, /init will run the Windows process creation logic if its argv[0] value doesn't match any of the known entrypoints.

See: WslEntryPoint() in src/linux/init.cpp.

Connecting to interop servers

When the user tries to execute a Windows process, the kernel will launch /init with the Windows process's command line as arguments.

To start a new Windows process /init needs to connect to an interop server. Interop servers are special Linux processes that act as bridges between Linux and Windows. They maintain secure communication channels (through hvsocket connections) with Windows processes (wsl.exe or wslhost.exe) to launch Windows executables.

Inside Linux, each session leader, and each instance of init has an associated interop server, which is serving via an unix socket under /run/WSL.

/init uses the $WSL_INTEROP environment variable to know which server to connect to. If the variable is not set, /init will try to connect to /run/WSL/${pid}_interop, with its own PID. If that doesn't work, /init will try its parent's pid, and then will continue to go up the chain until it reached init.

Once connected /init sends a LxInitMessageCreateProcess (WSL1) or a LxInitMessageCreateProcessUtilityVm (WSL2), which then forwards that message to the associated Windows process, which will launch the requested command and relay its output to /init.

See src/linux/init/binfmt.cpp


File: doc/docs/technical-documentation/localhost.md

Localhost

localhost is a WSL2 Linux process, created by mini_init. Its role is to forward network traffic between the WSL2 virtual machine, and Windows.

NAT networking

When wsl2.networkingMode is set to NAT, localhost will watch for bound TCP ports, and relay the network traffic to Windows via wslrelay.exe

Mirrored networking

In mirrored mode, localhost registers a BPF program to intercept calls to bind(), and forward the calls to Windows via wslservice.exe so Windows can route the network traffic directly to the WSL2 virtual machine.

Consomme networking

When wsl2.networkingMode is set to Consomme, the VM is given a virtio-net adapter whose host side is backed by Consomme, the user-mode NAT from the OpenVMM project. The guest sees a normal network (a DHCP-assigned address, a default gateway, and working DNS), but rather than going through a host NAT or bridge, its raw Ethernet frames are parsed by a user-mode process on the host and translated into ordinary host sockets. Because all traffic flows through standard host sockets, host networking policies (firewall, VPN routing, proxy settings) apply just as they would for any other host application.

Bound guest ports are tracked and forwarded to the host, optionally via wslrelay.exe.

See src/windows/common/ConsommeNetworking.cpp.

See src/linux/init/localhost.cpp.


File: doc/docs/technical-documentation/mini_init.md

mini_init

mini_init is the first executable that's launched when the WSL2 virtual machine starts. See WSL2 boot process for more details.

Virtual machine setup

mini_init is started when the kernel is done booting, and calls /init, which is mini_init. Like other standard linux init executables, mini_init starts by mounting /proc, /sys, /dev and other standard mountpoints.

mini_init then performs various configuration such as enabling crash dump collection, configuring logging via /dev/console and tty configuration.

Once everything is ready, mini_init connects two hvsockets to wslservice.

One of them, called the "mini_init" channel is used for messages sent by wslservice.exe. See src/shared/inc/lxinitshared.h for a list of messages and responses. Common messages are:

  • LxMiniInitMessageLaunchInit: Mount a virtual disk and start a new distribution. See init for more details
  • LxMiniInitMessageMount: Mount a disk in /mnt/wsl (used for wsl --mount)
  • EJECT_VHD_MESSAGE: Eject a disk
  • LxMiniInitMessageImport: Import a distribution
  • LxMiniInitMessageExport: Export a distribution

The other hvsocket channel is used to send notifications to wslservice.exe. This is used mainly to report when linux processes exit (which wslservice uses to know when distributions are terminated).

Networking configuration

As part of the boot process, mini_init also launches the gns binary which manages networking configuration

Other tasks

mini_init performs various other maintenance tasks such as:

  • Reclaiming unused memory
  • Launching the debug shell tty
  • Synchronizing IO when the virtual machine terminates
  • Resizing filesystem (for wsl --manage --resize)
  • Formatting disks (used when installing new distributions)

File: doc/docs/technical-documentation/plan9.md

Plan 9

Plan9 is a Linux process that hosts a plan9 filesystem server for WSL1 and WSL2 distributions. It's created by init in each distribution.

WSL 1

In WSL1 distributions, plan9 serves its filesystem through a unix socket, which can then be connected to from Windows.

WSL2

In WSL2 distributions, plan9 runs its filesystem through an hvsocket

Accessing the distribution files from Windows

From Windows, a special redirector driver (p9rdr.sys) registers both \\wsl$ and \\wsl.localhost. When either of those paths are accessed, p9rdr.sys calls wslservice.exe to list the available distributions for a given Windows user.

When a distribution path is accessed (like \\wsl.localhost\debian), p9rdr.sys calls into wslservice.exe via COM to start the distribution, and connect to its plan9 server, which allows the files to be accessed from Windows.

See src/linux/init/plan9.cpp

2. Official Technical Reference & Guides (microsoft/microsoft.github.io)

[microsoft.github.io](https://microsoft.github.io)

Many open source projects released by Microsoft products, services and teams also have
deployments powered by GitHub Pages on this domain.

To discover Microsoft-released open source projects, learn about Microsoft's open source
approach and other information, check us out online at opensource.microsoft.com.

If we can help answer questions about the open source program at Microsoft, you can
contact opensource at microsoft com - although we are not able to provide support
for projects through this mechanism.

Microsoft GitHub resources

Microsoft open source resources

Resources for Microsoft employees

How to identify an official Microsoft organization on GitHub

  • Official Microsoft GitHub orgs have a professional avatar and include a web address at Microsoft.com or an associated official domain
  • Official Microsoft orgs are Verified on GitHub - look for the domain verification indicator on GitHub