Update: Systemd support is now available in WSL2 and (update #2) now on both Windows 10 and Windows 11. As noted in my original answer (below) and others here, it's not required, and is opt-in.
Systemd requires that you use an updated WSL. See my answer on Ask Ubuntu for details on how to update to the latest release and enable the official Systemd support.
Original answer, which is still applicable in general to the way that WSL operates:
Great question -- So much fun stuff to cover here!
First, let's establish some terminology:
systemd is Linux's "master"-daemon, managing all other processes right after it has been started up and run its init-function.
First, a good point from @mascoj in the comments is that Systemd isn't required by Linux at all. It's certainly used in the vast majority of Linux distributions, but there are other alternatives (as @user1686's answer mentions) that both predate and have come since Systemd. Some distributions use these alternatives by default, and (personal opinion) some of these distributions may work better under WSL as a result.
At a high level, Systemd typically serves several functions:
- Init system: Performs boot-time system initialization (e.g. creates or cleans temp files, etc.)
- Run services at boot (e.g.
- PID 1 process: The master process under which all other processes live
- Process supervisor (a.k.a. process manager): Starts, monitors, restarts additional services
- Additional services (Systemd does a lot, e.g. logging, mounts, and much more)
Most of these functions can be handled separately, but Systemd "does it all".
Some distributions and systems don't rely on Systemd and do things less monolithically. For instance, some systems have the init system hand off control to a separate process supervisor at some point during the boot. The process supervisor may nor may not be PID1. If it's not, then typically the Init process remains as PID1 and the process supervisor runs under it. The process supervisor typically has a list of services that are desired at boot time, and it executes and monitors these.
Some distributions (Artix comes to mind, and I'm fairly certain Gentoo as well) allow you to mix and match from several different init systems and process supervisors.
Now let's cover the question in the title at a high level:
How does WSL/WSL2/WSLg work without Systemd?
It's important to understand that, when you are running a WSL2 distribution, that distribution is not running in a virtual machine. WSL2 itself is running a virtual machine with its own distribution (probably Mariner-based, if I had to take a guess).
Inside that hidden virtual machine is where your distribution is run in its own set of namespaces. If you run more than one distribution at the same time in WSL2, they are all running in that same VM, each with its own:
- PID namespace
- Mount namespace
- IPC namespace
- UTS namespace
- WSLg System Distribution (Windows 11 only)
However, they all share the following with the parent WSL2 VM (and thus each other):
- User namespace
- Network namespace
- Cgroup namespace
- Device tree (other than
- CPU/Kernel/Memory/Swap (obviously)
/init binary (but not process)
This is very, very similar to the way that container systems, such as Docker or Podman (and others), work.
And inside most (but certainly not all) containers, you'll find it rare that a process supervisor is running.
Most containers are told what services to start by the "outside" process (such as Docker) that starts them. In the case of WSL, there has traditionally been the
wsl command with which you tell WSL what services to start. E.g. (an oversimplified and not necessarily a great example):
wsl -e crond
However, one important difference is that, unlike traditional containers, WSL always has its own Init process that runs as PID1 (see below for why). For most other container types, PID1 is the process you tell it to start first.
While WSL1 isn't technically "running in a container/namespace" like WSL2, it does share the same Init concept for interoperability.
It's also important to remember that WSL1 doesn't support all Linux syscalls. When WSL1 first shipped, it's coverage was somewhere around 70%. It does a fairly great job of running a large number of tools, but I have a feeling that the number of units that Systemd normally attempts to bring up would probably expose some gaps.
WSLg runs in what is called a "System distribution", which is definitely based on the Mariner distribution. One WSLg system distribution is created for each WSL2 distribution that attempts to run GUI applications.
In this case, it's really up to Microsoft to determine how to launch the necessary services. You can create your own system distribution, if you'd like, and Microsoft provides a reference implementation to start with, but there's likely very little need for Systemd's functionality there.
None of that is to say that running a process supervisor in WSL (1 or 2) wouldn't be useful - It would in some cases. But personally, I'm glad that WSL leaves this up to the user. This allows it to operate like a container (fast startup, efficient resource usage) by default, but more like (but not quite) a full-blown "virtual OS" in other cases.
And the main question:
Now, out of curiosity I wanted to know, which process management WSL relies on instead of Systemd.
Let's break it down into the functions that we said Systemd handles above:
PID1/Init System: As mentioned above, WSL's proprietary
/init system is used for both these functions. This special
/init is needed because it handles the deep interop integration between Linux and Windows. Traditional Linux init systems such as Systemd have no idea how to handle this.
In theory, WSL2 could use Systemd to boot and set up some special services to handle the integration, but:
This would add overhead to a very streamlined startup
Some distributions don't use Systemd, so they would have to configure each distribution differently (best to leave this to the user, if needed).
It's possible that
/init would still need to be PID1 anyway, to continue to handle certain Interop features even after boot.
Since Systemd requires that it be PID1, that creates a bit of a conflict. I do think the Microsoft team is working on this, but it's clearly not something that has been solved yet.
Process supervisor/manager: WSL2 really doesn't have one by default. However, as @user1686 pointed out in another answer, that hasn't been a problem until recently. Scripts were created for each service, with entry points for the
service command (or similar) to start/stop/restart/status.
Ubuntu, at least, still provides many of these scripts for services. So when you want to start
sshd, for instance, you can just run
sudo service ssh start, which in turn calls its script. Same if you install Maridb (
sudo service mysql start).
However, some services don't provide SysVInit-style scripts. They may only provide Systemd units instead, at least on Systemd-based distributions. These just won't work (easily) on WSL distributions. See this answer where I cover the alternatives when that happens.
Run services at boot
Under Windows 10, there still isn't a great way to handle this. Of course, a WSL distribution doesn't really "boot", but it does have a defined "first start" where you might want to run something.
Under Windows 10, the best best was to either start the services manually or run them via your user startup files (e.g.
~/.bashrc). See this answer for some ideas on that.
But it sounds like you are on Windows 11 (since you mention WSLg), and in that case, there is a feature that allows you to specify a command (or series of commands) to run once when the distribution starts. Again, see this answer for the information on how to configure that.
Running a process manager at startup
Using these techniques, it's entirely possible to run whatever process supervisor you want, as long is it doesn't require that it be PID1.
Some that I've tried so far on WSL:
- Supervisord designed for running services in containers.
- dinit -- Available for Artix, an Arch-based distribution which has 5 different init/process manager options that you can use.
- s6, also available with Artix. This one had some issues under WSL2, and I think they were on the WSL2 side, but I can't be sure.
Both s6 and dinit tend to think they are running on a physical/virtual machine (naturally), so they attempt to do some startup that isn't necessary under WSL. I've been able to remove the unnecessary items, and then dinit, at least, runs quite well. I haven't rolled these into a reproducible set of instructions for others, yet, though.
It's even possible to run Systemd, by faking it out so that it's running as PID1 inside a new namespace inside a WSL2 (but not WSL1) distribution (which is, as we discussed, running in its own namespace already). I don't necessarily recommend it, personally, but lots of folks do. I cover some of this towards the end of this AU answer, so I won't repeat it here.