System has not been booted with systemd as init system (PID 1). Can't operate
I use WSL2 on Windows 11. I want to run the systemctl
command in Ubuntu 20.04, but it gives me the following error:
System has not been booted with systemd as init system (PID 1). Can't operate. Failed to connect to bus: Host is down
How can I fix it?
Solution 1:
Surprisingly, after 5 years or so of WSL, there doesn't seem to be a good, general-purpose "Systemd" question here on Ask Ubuntu. So this looks like a good one to use for that purpose.
The problem
In general, when you see either of the following two messages:
System has not been booted with systemd as init system (PID 1). Can't operate.
Failed to connect to bus: Host is down
Then it's typically the same root cause. In the case of systemctl
and attempting to start ssh
, you are seeing both.
The core problem, as mention in the comments, is that WSL doesn't use Systemd, even in distributions where it is the default. Instead, WSL currently uses its own /init
process as PID 1, which performs a few WSL-specific tasks that I mention in this answer (so I won't repeat them here).
And while WSL is (IMHO) a great way to have a full-featured Linux CLI in Windows (and recently, even GUI), the lack of Systemd does tend to make things more difficult in distributions that expect it to be there. Fortunately, Ubuntu is pretty good overall about being able to cope without Systemd.
How to handle the lack of Systemd
And regardless, Systemd at its core is just a (probably gross-oversimplification) "way of accomplishing system tasks". There is (usually? always?) a way of doing the same task without Systemd, and often more than one way.
-
Option 1: "The old way"
In Ubuntu on WSL, many of the common system services still have the "old"
init.d
scripts available to be used in place ofsystemctl
with Systemd units. You can see these by usingls /etc/init.d/
.So, for example, you can start
ssh
withsudo service ssh start
, and it will run the/etc/init.d/ssh
script with thestart
argument.Even some non-default packages such as MySql/MariaDB will install both the Systemd unit files and the old
init.d
scripts, so you can still use theservice
command for them as well. -
Option 2: "The 'manual' way"
But some services don't have a init-script equivalent, especially on other distributions. For simplicity, let's assume that the
ssh
init.d
script wasn't available.In this case, the "answer" is to figure out what the Systemd unit files are doing and attempt to replicate that manually. This can vary widely in complexity. But I'd start with looking at the Systemd unit file that you are trying to run:
less /lib/systemd/system/ssh.service
# Trimmed [Service] EnvironmentFile=-/etc/default/ssh ExecStartPre=/usr/sbin/sshd -t ExecStart=/usr/sbin/sshd -D $SSHD_OPTS RuntimeDirectory=sshd RuntimeDirectoryMode=0755
I've trimmed out some of the less relevant lines for understanding its behavior, but you can
man systemd.exec
,man systemd.service
, and others to see what most of the options do.In this case, when you
sudo systemctl start ssh
, it:- Reads environment variables (the
$SSHD_OPTS
) from/etc/default/ssh
- Tests the config, exits if there is a failure
- Makes sure the RuntimeDirectory exists with the specified permissions. This translates to
/run/sshd
(fromman systemd.exec
). This also removes the runtime directory when you stop the service. - Runs
/usr/sbin/sshd
with options
So, if you don't have any environment-based config, you could just set up a script to:
- Make sure the runtime directory exists. Note that, since it is in
/run
, which is atmpfs
mount, it will be deleted after every restart of the WSL instance. - Set the permissions to
0755
- Start
/usr/sbin/sshd
as root
... And you would have done the same thing manually without Systemd.
Again, this is probably the simplest example. You might have much more to work through for more complex tasks.
- Reads environment variables (the
-
Option 3: Run Systemd as PID 1 in a PID namespace/container
Finally, it's possible to get Systemd running under WSL. This is a fairly advanced topic, although there are multiple scripts and projects that attempt to simplify it. Even so, my personal recommendation is to make sure that you understand what is going on behind the scenes should you use one of these techniques.
Let's start with some of the more popular projects to enable Systemd in WSL:
- Genie
- WSL2-Hacks
- Distrod
I haven't personally run any of them, but all are open-source, and I've scanned the source to compare the techniques. At the core, each creates a new namespace or container where Systemd can run as PID 1.
You can see this in action by following the steps:
-
Run:
sudo -b unshare --pid --fork --mount-proc /lib/systemd/systemd --system-unit=basic.target
This starts Systemd in a new namespace with its own PID mapping. Inside that namespace, Systemd will be PID1 (as it must, to function) and own all other processes. However, the "real" PID mapping still exists outside that namespace.
Note that this is a "bare minimum" command-line for starting Systemd. It will not have support for, at least:
- Windows Interop (the ability to run Windows
.exe
) - The Windows PATH (which isn't necessary without Windows Interop anyway)
The scripts and projects listed above do extra work to get these things working as well.
Wait a few seconds for Systemd to start up, then:
sudo -E nsenter --all -t $(pgrep -xo systemd) runuser -P -l $USER -c "exec $SHELL"
This enters the namespace, and you can now use
ps -efH
to see thatsystemd
is running as PID 1 in that namespace.At this point, you should be able to run
systemctl
.And after proving to yourself that it's possible, I recommend exiting the WSL instance completely, then doing
wsl --terminate <distro>
on it. Otherwise, you will have some things be "broken" until you do. They can likely be "fixed", but that's beyond the scope of any one Ask Ubuntu question ;-). My recommendation is to refer to the projects above to see how they handle it. - Windows Interop (the ability to run Windows