It's honestly a great question, as I realized when I went through the various scenarios below. The way that WSL works here is, I have to agree, confusing. There are a number of "issues" that come up related to this on the WSL Github repo, but the reality is that this behavior is "by design".
From the WSL/Systemd announcement:
It is also important to note that with these change, systemd services will NOT keep your WSL instance alive. Your WSL instance will stay alive in the same way it did before, which you can (read more about here](https://devblogs.microsoft.com/commandline/background-task-support-in-wsl/).
In other words, WSL is designed to terminate Ubuntu in certain situations, but the linked post isn't very clear about exactly what those scenarios are. To understand them (and how WSL behaves) a bit better, let's start out with the (at least) four different ways you can start a background task or service (a.k.a. daemon) on Ubuntu on WSL:
Interactively, from the command line via the command itself or using the service
helper. E.g.:
sudo service cron start
# or even
sudo /usr/sbin/cron
This, of course, will work on any version of WSL, but the SysVInit service
may only work for certain distributions (such as Ubuntu) and services.
(Important) note that commands run inside your shell startup scripts are considered "interactive" for this purpose. That will come in handy in my ultimate (hacky) solution.
Interactively, as a background task from the shell. E.g.:
nohup sleep 100000 &
Under Windows 11, you can start a daemon automatically at WSL startup via /etc/wsl.conf
. E.g.:
[boot]
command = service cron start
And starting with WSL 0.67.6, using Systemd. This can happen either interactively (sudo systemctl cron start
), automatically via /etc/systemd
links, or as a dependency of another service. E.g.
sudo systemctl cron start
Note that the Snap daemon (snapd
) starts automatically via Systemd once enabled in WSL.
With those scenarios in mind, we need to look at when WSL will terminate Ubuntu. As I said, it's "confusing". I wish I could come up with a summary statement to describe the behavior, but I struggle with it. The best I can do is provide examples:
Summary
- Will not terminate
- Will not terminate
- Will terminate
- Will terminate
Details and examples
A service started interactively via the commandline will prevent WSL from terminating Ubuntu. We can demonstrate this by:
- Temporarily disabling Systemd in
/etc/wsl.conf
- Exiting Ubuntu
- Start PowerShell
wsl --shutdown
- Restart Ubuntu via
wsl ~
(if needed, wsl ~ -d Ubuntu-22.04
, etc.)
sudo service cron start
- Exit the shell
- Wait a minute (25 seconds, by default, should be sufficient) and check
wsl -l -v
to show that Ubuntu is still in the Running state.
wsl -e ps axjff
should show that cron
is still running, even though no shell is running.
A background task started interactively via the commandline will also prevent WSL from terminating Ubuntu. Following the previous example:
- With Systemd still disabled, from PowerShell,
wsl --shutdown
- Start Ubuntu (e.g.
wsl ~
)
- Run
nohup sleep 100000 &
- Hit Enter one extra time to dismiss the
nohup
message
- Exit the shell/Ubuntu back to PowerShell.
- Wait 30 seconds to a minute and
wsl -l -v
to show that Ubuntu is still running.
wsl -e ps axjff
should show that the sleep
command is still running, even though no shell is running.
A service/process started via /etc/wsl.conf
, on the other hand, will not prevent WSL from terminating Ubuntu.
Starting with the previous example (Systemd disabled)
In Ubuntu, sudo -e /etc/wsl.conf
and add the following:
[boot]
command = service cron start
Exit Ubuntu, and from PowerShell, wsl --shutdown
Restart Ubuntu via wsl ~
ps axjff
to show that cron
is running as a subprocess of one of the /init
parents.
Exit the shell/Ubuntu
After 30 seconds to a minute wsl -l -v
will show that Ubuntu is no longer running. It has been terminated.
A service/process started via Systemd will also not prevent WSL from terminating Ubuntu. Demonstration (although you are experiencing this):
Edit /etc/wsl.conf
and re-enable Systemd while disabling (commenting out or removing) the command
.
Exit Ubuntu
In PowerShell, wsl --shutdown
wsl ~
to start Ubuntu.
ps axjff
will show the Systemd services running and/or starting up.
After a minute:
sudo systemctl stop cron
sudo systemctl start cron
This has the effect, obviously, of simply stopping cron then restarting it. The point here is to show that even though we explicitly started cron
interactively, this will not prevent WSL from terminating Ubuntu.
Exit the shell/Ubuntu
After 30 seconds to a minute, wsl -l -v
will show that Ubuntu has been Stopped.
As for your particular question, since lxd
is simply a Snap, which is running in a containerized environment started by Systemd, it is getting terminated as well. Well, bummer ...
Solution
Hopefully there's a more permanent fix incoming, as one of the WSL developers did indicate a desire to keep distros running.
In the meantime, a solution (and there may, of course, be more) is to start a long-running process via your shell startup-files. In my case, I typically run keychain
.
There are a few things about Keychain that allow it to work nicely in this case:
- It's available in the default Ubuntu repositories
- It already starts a singleton instance of
ssh-agent
. In other words, if ssh-agent
is already running, it will attach to it rather than starting a new one.
- It can run quietly, and without interaction if no keys are added
To set this up:
sudo apt update && sudo apt install keychain -y
sudo -e /etc/profile.d/keep_wsl_running.sh
And add the following:
#!/usr/bin/env sh
eval $(keychain -q)
This script:
Runs when you start your shell (assuming most shells such as Bash and Zsh). Note that it will not run if you use Fish as your shell. If you (or any future reader) does want to use Fish (or another shell that doesn't process /etc/profile.d
), ask a separate question on how to handle this scenario. I do have a solution, but this answer is (as usual) long enough already ;-).
Evaluates the output of keychain
, so that it finds any existing ssh-agent
(or starts a new one, if not) and sets the environment variables for the shell to point to it.
-q
, as you probably imagine, simply runs keychain
quietly, without output
Having a the ssh-agent
running (that was started via /etc/profile.d
) will prevent WSL from terminating the Ubuntu distribution/instance/container. Ubuntu will continue running after you close the terminal window, and your lxd
(and other daemons/services installed by Snap) will stay up as well.
To allow Ubuntu to terminate gracefully, just get rid of the ssh-agent
. This can be done several ways, including:
keychain -k all
Of course, make sure that any other services that you started interactively are also gone. Once that condition is met, WSL will gracefully terminate Systemd and its units/services.
There's one corner case here, and that's if you start a wsl -u root
session. In that case, ssh-agent
will also be running as root, and you'll need to sudo keychain -k all
.
bash.exe
has nothing to do with Ubuntu (the .exe should be clue enough); 2. Please understand this quite obvious situation: when the cli for Ubuntu is closed, Ubuntu is closed (granted, maybe not obvious for you because you're very confused). Then 3. anything you install in Ubuntu needs Ubuntu running, the same way any software installed in the guest OS (VM) CANNOT run by itself in the host OS. There's absolutely nothing else to understand here.wsl --status
,wsl --version
, andcmd.exe /c ver
? Would you add that info to your question? Note thatwsl --version
may not work, depending on the actual version. Thanks! – NotTheDr01ds Oct 18 '22 at 01:19bash.exe
is the legacy (now deprecated) way of launching Ubuntu on WSL. It was a horrible name, clearly, but that's why it was changed towsl.exe
. – NotTheDr01ds Oct 18 '22 at 11:49