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.
An X11 application like xclock sends commands to the “terminal” to display graphic information. X-Win32 receives these commands over the network and writes to its application window on your Windows desktop. If you boot Linux as the operating system of your hardware PC, then Linux itself has an X11 terminal emulator built into its OS, and when it receives commands from an application it writes the data to the hardware monitor using the driver for you hardware video adapter card. In a VM, Linux does the same thing, but now the VM supervisor (Microsoft Hyper-V, Oracle VirtualBox, or VMWare) emulates the video adapter card, receives the low level hardware commands sent to the card, and generates a window that contains the what the monitor would show if there were a real monitor.
Microsoft does not want to add an X11 terminal emulator to Windows 10, and it already has the Hyper-V capability to display the image of a Linux PC monitor on the Windows desktop. So to add support for graphics applications to WSL, Microsoft has decided to put all the X11 code inside the WSL VM and use the same Remote Desktop Protocol programs that it uses to display the emulated screen of VMs and also to connect through the network to another computer and operate it remotely.
However, rather than basing this code on the old X11 protocol, they have decided to use the newer Linux screen API called Wayland, which is implemented by a program called Weston. It happens that Weston already has some support for Remote Desktop Protocol, so Microsoft just had to add some missing features rather than starting from scratch.
If you want to see the Gnome desktop of a real Linux system, then create a Hyper-V VM with Ubuntu or your favorite distribution. WSL is designed to run Linux programs integrated into Windows. Having two separate desktops, even if one is in a Remote Desktop window, does not provide real integration. What we want is the ability to run xclock and have just the clock window generated by the app to appear on the Windows desktop, and we want it to be mostly indistinguishable from the Windows apps. There will always be some problem with the Linux convention of having a three button mouse, but where possible a Linux GUI program should look just like it was a Windows GUI program.
Remote Desktop has support for this too, though it is less widely used. Microsoft created it originally to allow a Windows 10 desktop user to click on an application in the Start menu and have it launch a program on some server in the machine room. Today, the program may run in the Azure Cloud. The application looks the same as other programs that are running locally on your machine. There are two versions of this protocol. When you connect through the network to a physical server, it is called RAIL. When you connect to a VM using Hyper-V support, it is called VAIL.
The last problem is how to insert all this support seamlessly and invisibly into the current WSL 2 environment. X11 or Wayland/Weston are “user mode” applications that are outside the kernel. In WSL 2, everything that is not in the Kernel is part of the distribution you download from the Microsoft Store. If you choose Ubuntu, Microsoft wants to minimize the amount of new code that would have to be added to Ubuntu by Canonical (and Alipine, and Arch, and Suse, …).
So they decided that the graphical support, including the Weston code, would be packaged in a separate Microsoft provided Linux user mode distribution that runs side by side with, for example, the Ubuntu distribution that Canonical puts in the Windows Store. That way a (mostly?) vanilla Ubuntu could just run a GUI application that would talk to what it thinks is an X11 or Wayland terminal emulator on another computer, only that “other computer” is just another WSL Linux container sitting side by side next to Ubuntu.
Docker already does a similar sort of thing when you use Docker Desktop for Windows to install Docker in both Windows 10 and as many WSL Linux systems as you have installed. Once it is installed, you see two additional WSL Linux “distributions” that run side by side with the distribution you use. You didn’t create them directly and you don’t start, stop, or configure them. They provide support for Docker in WSL while hiding from the distribution the details of how Docker decided to implement its functions under WSL:
PS C:\Users\gilbert> wsl -l Windows Subsystem for Linux Distributions: Ubuntu-20.04 (Default) docker-desktop-data docker-desktop
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.