Skip to end of metadata
Go to start of metadata

You are viewing an old version of this content. View the current version.

Compare with Current View Version History

« Previous Version 20 Next »

WSL 2 is the Linux aspect of Windows. It supports the direct execution of a Linux program on Windows by providing the libraries of a distribution like Ubuntu and the system services of a real Linux Kernel. It is a hybrid environment that is part Windows, part Linux. If you want the true Linux experience, use Hyper-V “Quick Create” to build a real Linux VM.

WSL 2 lets you slide between Windows and Linux seamlessly. All your Windows files are available to Linux programs, and all you Linux files are available to Windows programs. You can create *.bat or Powershell scripts that mix Windows and Linux commands and pipe data back and forth. Since you can run bash, sed, awk, grep, etc. now in Windows, you don’t need old emulation systems like Cygwin.

WSL, like Docker Containers, run in Linux “single user” mode, where the only interface is a terminal session and the only programs running are ones you start manually. All Linux systems can be started this way to do maintenance and recovery, but if you boot Linux normally it will start configured background services (daemons). In single user mode, there is no sshd to login through the network or snapd to manage snap packaged programs. The original WSL 1 was architecturally constrained. WSL 2 can start systemd and start services, but for now Microsoft seems to want to preserve your ability to switch back and forth between WSL 1 and WSL 2 in a few minutes, so by default you get the WSL 1 constraint.

When you run an distribution like Ubuntu under WSL, it does not offer to install all the packages that you might have available on an Ubuntu VM. For now, you will not be offered packages that expect a full graphic desktop or depend on daemons. In particular, since snapd is not running, you will not see snaps. Simple graphic programs will still be offered:

gilbert@wholewheat:/mnt/c/Users/gilbert$ xclock
Command 'xclock' not found, but can be installed with:
sudo apt install x11-apps

WSLG - Graphics Applications (Coming)

X11 connects a program running on Linux to a terminal emulator which may be on another computer. It does not depends on background services, so it can run from WSL to Windows if you install an X Terminal emulator program, like X-Win32 from the Yale Software Library. You need to set the DISPLAY environment variable in WSL Linux and run an x11 program. For example, after starting X-Win32, you can open a Windows command prompt and (assuming your Windows has a particular IP address) type:

bash -c "export DISPLAY=192.168.1.44:0 && xclock"

And the Linux GUI clock appears on your Windows screen.

However, you don’t need to install X-Win32 to run an entire Linux VM on Hyper-V. On a PC Linux takes the X11 protocol and writes the output to the hardware monitor through the video adapter card, and in a VM it writes to a virtual video card that Hyper-V translates to an image in a window on the screen. Since there are other protocols than X11 and Microsoft does not want to be dependent on a third party terminal emulator, they are adapting Remote Desktop Protocol for their WSL Graphics support.

Also, instead of using the old X11 protocol, the Linux side of their work uses the Wayland protocol implemented through the Weston software component.

However, this is still Microsoft and Windows. Unlike a Hyper-V VM, Microsoft is not interested in popping up a window on your screen with a Gnome desktop. There already is a Windows desktop and they don’t need another one. I already showed you the trick above. If you can run xclock from the Windows Command Line , then you can also create a Shortcut in the Windows start menu to do effectively the same thing.

Most desktop users don’t know that there is a single application, single window version of Remote Desktop Protocol. It was created to run an application on a server in the machine room (or today on a server in Azure) but make the application program look to the user just like any other program on the desktop. There are a pair of names for this: RAIL (if the desktop and server are connected over the network) and VAIL (if the server is a VM and the connection uses the Hyper-V vmbus).

Obviously, to set up a Wayland/Weston support environment would require substantial changes to the current WSL “distributions” available from the Windows Store (Ubuntu, Alpine, Arch) and Microsoft doesn’t want the graphics support to have to be installed into each distro. This problem has already been addressed by Docker to install and support the Docker Engine running in WSL 2 on any distribution. After installing Docker Desktop for Windows and clicking the “Use WSL 2” checkbox, you will see that additional “distributions” have been added to your list:

PS C:\Users\gilbert> wsl -l
Windows Subsystem for Linux Distributions:
Ubuntu-20.04 (Default)
docker-desktop-data
docker-desktop

So in the same spirit, when WSLG is added by Microsoft to support GUI applications running in WSL, they will add a “system distro” that runs side by side with the Linux distro. The Weston manager and the communication with Windows using RAIL/VAIL will be in that separate environment, making changes to the Ubuntu or Alpine distribution minimal.

It would be tedious to have to define a Windows shortcut yourself for every Linux GUI program you want to launch from the Windows Start menu. So the plan is eventually to read all the .desktop files installed in a WSL Linux distribution and generate the Start Menu entries automatically. Exactly how this will be done has not been disclosed and it is not trivial. You can run more than one Linux distribution in WSL at the same time, and you might want Windows shortcuts for “Firefox running in WSL Alpine” and “Firefox running in WSL Ubuntu” and you can run both side by side in the Windows screen. It is easy to set this up, but it is hard to figure out how to generate the shortcuts automatically.

Some WSL Implementation Internals

Bell Labs created Unix when computers were big expensive machines shared by users. Then Personal Computers came along, and the need was to control networks of small cheap computers. The Unix developers started work on a successor to Unix that would look like one big operating system that was spread out through the network across a number of client and server machines. The system was called “Plan 9” and to make it work they needed programs and services to communicate over a protocol that worked the same between two components running on the same computer or the same two components split on two different machines connected by the network. The protocol was called “9P”. Since WSL is specifically intended to create the impression that there are Windows programs and files and Linux programs and files but they are all part of one Windows OS, Microsoft decided to adopt “9P” as the framework.

In concrete terms, consider the following two command entered at the Windows Command Prompt:

C:\Users\gilbert>tasklist | find "firefox"
firefox.exe                  24640 Console                    1    587,668 K
firefox.exe                  12656 Console                    1     67,300 K
C:\Users\gilbert>tasklist | wsl grep "firefox"
firefox.exe                  24640 Console                    1    587,832 K
firefox.exe                  12656 Console                    1     67,300 K

The first command runs the Windows tasklist.exe and uses the traditional PC DOS “find” command to select specific lines from the program output. The second line uses wsl.exe to send the Linux command grep “firefox” to WSL. The standard output from the tasklist.exe is piped (using 9P) to the standard input of the Linux grep program. The standard output of grep is piped back to Windows and is read by the Command Prompt, which prints the output to the screen. You can find many systems that provide Linux program converted to run in Windows, but here we are not using some “grep.exe” windows emulator program. We are piping data back and forth between a real Windows program and a real Linux program running side by side in the same windows environment. It works the other way:

C:\Users\gilbert>bash
gilbert@wholewheat:/mnt/c/Users/gilbert$ tasklist.exe|grep firefox
firefox.exe                  24640 Console                    1    593,900 K
firefox.exe                  12656 Console                    1     67,776 K

We run the bash.exe program to move to the WSL Linux shell environment. Now in WSL Linux, we type a normal Linux command except that the executable program name ends in .exe. When Bash sees a windows executable program as a Linux command, it uses 9P to ask Windows to run the program and pipe the output back to it. So you can both run Windows programs in the middle of a Linux command, and run Linux programs in the middle of a Windows command, and pipe data back and forth automatically.

Windows expects commands to be .exe or .bat files (or other configured extensions), but Linux executables normally have no extension. So the convention in Windows is to type “wsl commandname” to run a Linux command using the wsl.exe program. Linux does not expect programs to have extensions, so in WSL Microsoft has added support to recognize either the .exe extension or the format of a Windows .exe file.

User mode programs talk across systems using 9P. Microsoft already had a separate convention to allow OS Kernels in Hyper-V VMs to talk back to the Windows host using the Hyper-V virtual bus. Microsoft has a lot of VMs in its Azure Cloud that run Linux, and to make that work most efficiently, they had already adapted the Linux Kernel to use Hyper-V communication for services like disk and LAN I/O. They built that support into the WSL Linux Kernel.

For example, a program opens a file path name, and the OS file system turns the file name into a file location (a set of relative block numbers in the disk partition). In a real computer, this in turn gets translated into a hardware LBA, a relative sector number on the disk, which is in turn converted to a SATA or SCSI controller hardware command. If you do this in a VM, then the Hyper-V, VMWare, or VirtualBox supervisor has to translate the SATA or SCSI command back to an LBA. It is more efficient to put a Hyper-V specific driver in the Linux Kernel that stops before it emulates a disk controller and ships the LBA from the Linux Kernel to the Windows Kernel where it can be translated to a offset in an open VHDX file containing a disk image.

There is one more important optimization to make WSL start up instantly. A normal VM has a designated boot disk. When the VM starts up, an emulated BIOS or EFI firmware loads boot data off the virtual boot disk, which on a Linux system is a component named “Grub”. About 50 years ago IBM showed that there was a different way to load an OS into a virtual machine, and today various vendors are rediscovering it. The trick is to book an OS into a virtual machine until it is completely initialized but has not yet run any programs. Now stop the VM and take a snapshot of its memory and save that checkpoint to disk. When you want to run that OS, simply restore the checkpoint back to virtual memory and start it up. So the WSL Linux Kernel does not “boot” up, does not have a Grub, and does not go through an emulated BIOS. It simply appears “poof” already loaded into memory and begins running. Well, there is a slight bit of initialization for differences between AMD or Intel CPUs, but that is much less work than a real boot.

The Distros

Once you have WSL 2 itself, you go to the Windows Store and select one or more “distributions” that have been contributed by third parties. Canonical Ubuntu is the vendor that has worked most closely with Microsoft to make WSL run smoothly and is the recommended choice here, but you can also download versions of Alpine and SUSE and a third party (Whitewater Foundry) distributes versions of Red Hat systems that have been converted to WSL.

A WSL Distribution looks like a persistent container. The Ubuntu that runs in WSL has roughly the same features, programs, and restrictions as the Ubuntu image you download from Docker Hub. This was a requirement for WSL 1 and has been carried forward to WSL 2. If you find that there is no support for a package you need, then you may require a VM to run it.

What you download from the Store (Ubuntu 20.04 or Alpine) is a store package with a compressed virtual disk image containing a specific selected set of user mode Linux libraries and executables placed in /bin, /etc, /lib, and other directories ready to run a Linux system when you start it up. The package files are stored in the Windows system directories.

WSL must be instructed (though normally this is implicit and not visible to the user) to use the package to create an instance of the distribution by decompressing the VHDX file and storing a working copy in the home directory of the current user.

At any time you can discard your current instance and start over with an empty fresh copy of the original package disk. If you have more than one userid defined on your computer, even if they are just alternate names that you use for different purposes, then each of these users gets a separate instance of a WSL distro. This is necessary because even if a user is not an admin of the Windows system, he always has root privileges in his private copy of a WSL Linux instance.

There may be slight differences in the punctuation of the “Ubuntu 20.04” package that you download and the “Ubuntu-20.04” instance you create from it. Microsoft does not make a big deal of it, and generally you don’t ever think about packages unless you are in the Store application itself. When the “wsl” command is documented to have a <distro> parameter, this is really the name of an instance.

You can create more than one instance of Ubuntu 20.04 under the same user, but Microsoft does not explain how to do it in their documentation. The Windows “wsl --export” command is documented to backup or checkpoint the current state of a WSL instance to a tar file with a name and location you choose. Nominally this is a way to restore a good environment after you try something that fails terribly, or to uninstall a component and its dependent packages that you find to be a bad idea. However, you can use the “wsl --import” command to create a new instance with a new name instead of just restoring an existing instance. In parameters of the command, you choose the new instance name, and specify a directory where you want the instance files stored.

The “wsl --import” command can also be used to create a new WSL instance based on a “backup” tar file that you did not create, but instead received from a coworker. You will also find that new versions of Ubuntu that are not yet available on the Store (or are still in Beta) are available every few weeks as files named something like ubuntu-20.04-server-cloudimg-amd64-wsl.rootfs.tar.gz in the Canonical site https://cloud-images.ubuntu.com/releases/. Remember to unzip the file because “wsl --import” takes a tar and not a tar.gz file.

Whichever “distro” instance of Linux is currently designated as the Default becomes the environment in which you can conveniently escape from Windows to Linux (and then back from Linux to Windows) as you type in commands or run scripts. Once you get used to it, you can slip back and forth between the two environments freely.

If you install more than one package and create and run more than one instance, you will discover that all instances share the same copy of the Linux Kernel. They run as a type of container on top of the Kernel, and share the same LAN adapter, IP address, and port numbers. So if you are running Tomcat on port 8080 in Ubuntu WSL, that port is busy and cannot be used in Alpine WSL.

The Good

If you are running Windows Powershell or Command Prompt and you want to run a single Linux command, just precede the command with “wsl”.

PS C:\Users\gilbert> wsl ps
  PID TTY          TIME CMD
 7064 pts/3    00:00:00 ps

The Windows “wsl ps” command runs the wsl.exe program. It takes everything that follows the program name and sends it to Linux to run as a single process. The standard output of the Linux process is sent back to Windows where it becomes the standard output of the wsl.exe program. From the point of view of the program running wsl.exe, it is just a Windows program that runs like any other executable.

Each Windows disk letter appears to be mounted to WSL Linux under the /mnt directory. Thus in WSL Linux, /mnt/c is the Windows C:\ disk. Each WSL Linux instance is accessible from Windows as if it were a share from a network host with the computer name “wsl$”. Therefore, the /usr/local/ directory of the Ubuntu-20.04 instance is \\wsl$\Ubuntu-20.04\.

PS C:\Users\gilbert> wsl pwd
/mnt/c/Users/gilbert

PS C:\Users\gilbert> dir \\wsl$\Ubuntu-20.04\usr\local
    Directory: \\wsl$\Ubuntu-20.04\usr\local
Mode                 LastWriteTime         Length Name
----                 -------------         ------ ----
d----            9/5/2020  2:23 PM                bin
d----           4/23/2020  2:40 AM                etc
d----           4/23/2020  2:40 AM                games
d----           4/23/2020  2:40 AM                include
d----           4/23/2020  2:40 AM                lib
d----           4/23/2020  2:40 AM                sbin
d----           7/16/2020 11:19 PM                share
d----           4/23/2020  2:40 AM                src

The wsl.exe program only runs a single Linux executable as a single process. If you want to enter an entire line of Linux commands, remember that interpreting a line of command with “|” or “&&” separators is a function of a shell program. For convenience there is a separate bash.exe on Windows that makes it easy. You can of write a script file and run it, but remember that script files have to be edited with Linux line ends and not Windows line ends. For a single line, use the -c parameter and put the Linux command line in quotes:

PS C:\Users\gilbert> bash -c "ps -ef|grep vscode"
gilbert   6640  6639  0 Sep04 pts/2    00:00:00 sh -c "$VSCODE_WSL_EXT_LOCATION/scripts/wslServer.sh" a0479759d6e9ea56afa657e454193f72aef85bd0 stable .vscode-server 0
gilbert   6641  6640  0 Sep04 pts/2    00:00:00 sh /mnt/c/Users/gilbert/.vscode/extensions/ms-vscode-remote.remote-wsl-0.44.5/scripts/wslServer.sh a0479759d6e9ea56afa657e454193f72aef85bd0 stable .vscode-server 0
gilbert   6646  6641  0 Sep04 pts/2    00:00:00 sh /home/gilbert/.vscode-server/bin/a0479759d6e9ea56afa657e454193f72aef85bd0/server.sh  --port=0 --use-host-proxy --enable-remote-auto-shutdown
gilbert   6648  6646  0 Sep04 pts/2    00:00:05 /home/gilbert/.vscode-server/bin/a0479759d6e9ea56afa657e454193f72aef85bd0/node /home/gilbert/.vscode-server/bin/a0479759d6e9ea56afa657e454193f72aef85bd0/out/vs/server/main.js  --port=0 --use-host-proxy --enable-remote-auto-shutdown
gilbert   6666  6648  0 Sep04 pts/2    00:00:01 /home/gilbert/.vscode-server/bin/a0479759d6e9ea56afa657e454193f72aef85bd0/node /home/gilbert/.vscode-server/bin/a0479759d6e9ea56afa657e454193f72aef85bd0/out/bootstrap-fork --type=watcherService
gilbert   6692  6648  0 Sep04 pts/2    00:00:11 /home/gilbert/.vscode-server/bin/a0479759d6e9ea56afa657e454193f72aef85bd0/node /home/gilbert/.vscode-server/bin/a0479759d6e9ea56afa657e454193f72aef85bd0/out/bootstrap-fork --type=extensionHost --uriTransformerPath=/home/gilbert/.vscode-server/bin/a0479759d6e9ea56afa657e454193f72aef85bd0/out/vs/server/uriTransformer.js --useHostProxy=
gilbert   7070  7069  0 11:10 pts/3    00:00:00 /bin/bash -c ps -ef|grep vscode
gilbert   7072  7070  0 11:10 pts/3    00:00:00 grep vscode

The Windows bash.exe has no parameter for distribution name, so it can only communicate with the default instance of WSL Linux. It sends the command line to Linux, which runs ps and pipes the output to grep. The standard output from grep is captured and sent back to windows where it becomes the standard output of bash.exe.

If you don’t put the entire command line in quotes, the Windows Command Prompt or Powershell environment will stop when it hits the unquoted “|” because that is a special character in both Windows and Linux shells. There is no grep.exe in Windows (unless you added it yourself) but roughly the same thing can be done with the Powershell Select-String cmdlet:

PS C:\Users\gilbert> wsl ps -ef|select-string "vscode"

gilbert   6640  6639  0 Sep04 pts/2    00:00:00 sh -c "$VSCODE_WSL_EXT_LOCATION/scripts/wslServer.sh" a0479759d6e9ea56afa657e454193f72aef85bd0 stable .vscode-server 0
gilbert   6641  6640  0 Sep04 pts/2    00:00:00 sh /mnt/c/Users/gilbert/.vscode/extensions/ms-vscode-remote.remote-wsl-0.44.5/scripts/wslServer.sh a0479759d6e9ea56afa657e454193f72aef85bd0 stable .vscode-server 0
gilbert   6646  6641  0 Sep04 pts/2    00:00:00 sh /home/gilbert/.vscode-server/bin/a0479759d6e9ea56afa657e454193f72aef85bd0/server.sh  --port=0 --use-host-proxy --enable-remote-auto-shutdown
gilbert   6648  6646  0 Sep04 pts/2    00:00:05 /home/gilbert/.vscode-server/bin/a0479759d6e9ea56afa657e454193f72aef85bd0/node /home/gilbert/.vscode-server/bin/a0479759d6e9ea56afa657e454193f72aef85bd0/out/vs/server/main.js  --port=0 --use-host-proxy --enable-remote-auto-shutdown
gilbert   6666  6648  0 Sep04 pts/2    00:00:01 /home/gilbert/.vscode-server/bin/a0479759d6e9ea56afa657e454193f72aef85bd0/node /home/gilbert/.vscode-server/bin/a0479759d6e9ea56afa657e454193f72aef85bd0/out/bootstrap-fork --type=watcherService
gilbert   6692  6648  0 Sep04 pts/2    00:00:11 /home/gilbert/.vscode-server/bin/a0479759d6e9ea56afa657e454193f72aef85bd0/node /home/gilbert/.vscode-server/bin/a0479759d6e9ea56afa657e454193f72aef85bd0/out/bootstrap-fork --type=extensionHost --uriTransformerPath=/home/gilbert/.vscode-server/bin/a0479759d6e9ea56afa657e454193f72aef85bd0/out/vs/server/uriTransformer.js --useHostProxy=

Powershell ends the wsl.exe command at the “|” and wsl.exe only sends the “ps -ef” to Linux to execute. The standard output of ps is piped back to Windows and Powershell sees it as the standard output of the wsl.exe program. Powershell then pipes that string on to Select-String which filters the lines that contain “vscode”. The output is roughly the same, except that you don’t get lines for the grep process that isn’t running.

Similarly, if you are in WSL Linux and you want to run a Windows command, just add the “.exe” file suffix on the end of the command:

gilbert@wholewheat:/mnt/c/Users/gilbert$ tasklist.exe|grep firefox
firefox.exe                  26904 Console                    1    424,532 K
firefox.exe                  28724 Console                    1    107,920 K
firefox.exe                  28404 Console                    1    315,080 K
firefox.exe                  17492 Console                    1    102,580 K
firefox.exe                  22560 Console                    1     16,240 K
firefox.exe                   5076 Console                    1    122,604 K
firefox.exe                  24172 Console                    1    531,812 K
firefox.exe                  25364 Console                    1    100,400 K
firefox.exe                  31040 Console                    1     72,940 K

Tasklist.exe is the Windows Command Prompt equivalent of Linux “ps -ef”. Linux is agnostic about whether executables have or don’t have a file type. The Microsoft Linux Kernel, however, knows about .exe and Windows executable file formats. When you try to run such a file in Linux, it sends the request back to Windows for execution, and the standard output of tasklist.exe is then sent back to Linux as standard output from the program. The shell in Linux then pipes that standard output to grep which filters the lines and the resulting standard output is printed out.

You may wonder at this point how Linux found tasklist.exe in its Path. The answer is that when the WSL Linux environment is created, the current Windows path is imported into Linux and is converted to the Linux equivalent fully qualified file path. So where C:\Windows\System32 is in your Windows Path, WSL Linux will append a /mnt/c/Windows/System32 to its path. Therefore, all windows executables are automatically available to WSL Linux just by typing their full *.exe name.

To be comprehensive, we should note that Powershell has its own Get-Process cmdlet to do the same thing. However, Powershell cmdlets are not standalone executables and can only run within the environment set up by running the Powershell program. Powershell has the same “-c” parameter to run one line and then exit, so look at one last example that runs in Linux but runs something in Powershell on Windows:

gilbert@wholewheat:/mnt/c/Users/gilbert$ pwsh.exe -c Get-Process|grep firefox
     96   194.24     119.68      82.39    5076   1 firefox
     57    71.11     101.78      19.34   17492   1 firefox
     16    19.88      15.86     254.45   22560   1 firefox
    158   582.25     527.08     328.27   24172   1 firefox
     85    78.95      96.77       1.61   25364   1 firefox
    239   394.20     421.05     454.61   26904   1 firefox
    137   395.53     314.20      96.81   28404   1 firefox
     95   393.02     106.35     306.20   28724   1 firefox
     75    45.83      50.68       0.36   31040   1 firefox

Here WSL Linux discovers that the pwsh.exe file is a Windows executable, so it sends the command to Windows. The “-c Get-Process” runs the cmdlet in Powershell and returns text as standard output, which is sent back to Linux and piped on to grep.

The Ugly

Assuming I am just a Dummy, when I am asked to create a userid and password in WSL 2 Linux, I will probably use the same userid and password I have in Windows. Then there is a “gilbert” in Windows and a “gilbert” in Linux with C:\Users\gilbert as the Windows home directory and /home/gilbert as the Linux home directory and they are two different directories on two different file systems with different content.

From Windows, you specify a user with the “wsl.exe -u xxxx” parameter. There is no password, and you can specify any username in Linux, including “root”. If you choose a different user than root, then Linux enforces the standard file permission rules for users and groups, but because there are no passwords this is just a pretend security check. If you do not specify a user, then the default user (the user created when you start the distro up for the first time) is used. The real data security comes from the fact that each WSL instance is private to the user that created it, and the disk image of files is stored in his home directory.

When you issue the wsl.exe or bash.exe commands in Windows, the subsequent command is located by using the Linux path. If a file in the Linux path has a name that ends in “.exe” and is a Windows executable, then it runs in Windows. To make this seamless, WSL adds all the files in the Windows path onto the end of the initial Linux $PATH environment variable (although the file names are converted from the C:\xxx syntax in the Windows environment to a /mnt/c/xxx syntax in the Linux $PATH.

The Tomcat Example

Most Yale programs run under the Tomcat Web server. Tomcat is written in Java and by default serves data over internet port 8080. Since Java runs in every type of system, it is useful to consider what is different when you move it from one environment to another.

Consider running Tomcat in the old WSL 1 where programs ran through an emulation layer. Here there is only one OS and only one Kernel, and the LAN adapters, IP addresses, and port numbers are shared by all programs without regard to whether they run in Windows mode or Linux mode. You can run Tomcat in Linux mode on port 8080 in exactly the same way you run it as a Windows program.

This means you could run Tomcat in WSL 1 Linux and connect to it with your Windows browser using the URL “http://localhost:8080/”.

Now convert the WSL Linux from WSL 1 to WSL 2. Because WSL 2 run in a Linux Kernel and because at this time Microsoft was only able to create a virtual LAN adapter with its own IP address, the IP address of WSL Linux no longer matches the IP address of Windows.

PS C:\Users\gilbert> Get-NetIPAddress|where -Property PrefixOrigin -eq "Dhcp"|select ipaddress
192.168.1.42
PS C:\Users\gilbert> bash -c "ip address|grep eth0"
4: eth0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc mq state UP group default qlen 1000
    inet 172.28.72.51/20 brd 172.28.79.255 scope global eth0

Windows has a native IP address of 192.168.1.42 on my home network and any other computer on that network can access it, however WSL Linux has an IP address of 172.28.72.51 on a virtual private network that connects it just to the Windows host. There is a NAT so it can use that virtual network to get to the outside world, but only the host computer has a connection to the virtual network with that address.

If you have more than one distro or instance, they all share the same Kernel and therefore the same virtual LAN and IP address. You can run Tomcat on any one of them, but if you try to run it twice the second one will fail because the 8080 port is in use.

However, it is seldom a requirement to access something you are running in Tomcat from a different machine. Since the common practice when testing Tomcat from a browser on the Windows host is to connect to the “localhost” hostname, Windows currently has a special port forwarding hack to handle that one case.

Any program running in a WSL 2 instance that tries to bind to a port number of the loopback IP address 127.0.0.1 or the wildcard 0.0.0.0 (because it includes the loopback address as well as real addresses) gets this system call trapped by the WSL Linux Kernel and a message is sent to a proxy program running in Windows to bind to the same port number on the Windows loopback and forward traffic from Windows to WSL.

So Tomcat in one of the WSL 2 instances binds to Port 8080 on wildcard IP address 0.0.0.0. Because this includes the WSL loopback adapter, a message is sent to the Windows proxy task and it binds to port 8080 on IP address 127.0.0.1. For now, it does not bind to any real IP address on any real adapter, so this only affects programs running on the Windows host system and only if they use “localhost” or “127.0.0.1” in their URL. So if Firefox naviagates to “http://localhost:8080” it connects to the proxy, which forwards the request to http://172.28.72.51:8080/ which is Tomcat running in WSL 2.

If you want a more general solution where other computers on other hosts can connect to your Tomcat running on WSL, you are going to have to set up your own port forwarding proxy.

Unless you run Tomcat in the Docker Engine under WSL 2. When WSL 2 is installed on Windows 10, Docker regards it as the best environment to run Linux containers. If you run Tomcat in a container on WSL 2 rather than running it as a native Linux program on the same WSL 2 instance, then Docker has its own proxy running in the Windows host environment. When the Engine processes a “docker run -p 8080:8080 …” then it sends a message to its proxy process in Windows to bind to the 8080 port on Windows and forward traffic to the container. Tomcat under Docker in WSL 2 can be reached by other computers in the real network, whereas Tomcat running natively in WSL 2 Linux is not visible.

Docker Desktop for Windows

When you install Docker Desktop for Windows on a Windows 10 system, there is a checkbox to use WSL 2. You want to select this option because it is faster, simpler, and more generally useful. The Windows installer for Docker will also install the docker command and Engine on the default instance of WSL Linux. Later on you can use the Docker configuration window to also install the same Docker components on other WSL instances.

You should not try to install Docker in a WSL Linux instance with a package manager like apt. You want let Docker Desktop for Windows install it instead.

After installation, there is a docker command in Windows and one in WSL Linux. The WSL Linux command only talks to the WSL Linux Engine and therefore only to Linux containers. The docker command in Windows can be switched between the Windows Engine (which runs only Windows Containers) and the WSL Linux Engine (which runs only Linux containers).

Each Engine maintains its own repository of images and manages its own set of running containers. If you switch the Windows docker command from one Engine to another, the containers that were started continue to run. If you switch to Windows Containers, then remember that the WSL Linux docker command continues to be connected to the Linux Engine and you can use it to manage Linux containers without switching the Windows command back.

  • No labels