Skip to main content
The 2026 Annual Developer Survey is live— take the Survey today!.
I cannot comment on your answer, but I needed to run wsl --update before your answer worked
Source Link
scorpwasp

Some people may need to run wsl update:

wsl --update

Some people may need to run wsl update:

wsl --update
Quick update per comments
Source Link
NotTheDr01ds
  • 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 of systemctl with Systemd units. You can see these by using ls /etc/init.d/.

    So, for example, you can start ssh with sudo service ssh start, and it will run the /etc/init.d/ssh script with the start 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 the service command for them as well.

    To autostart services (a la systemctl enable) at startup, see this answer on Super User for how to do this with /etc/wsl.conf.

  • Option 2: Docker

    Many packages/services are available as Docker images. Docker runs great under Ubuntu on WSL2 (specifically WSL2; it will not run on WSL1). If there's not a SysVinit "service" script for the service you are trying to start, there may very well be a Docker image available that runs in a containerized environment.

    Example: Elasticsearch, as in this question and my answer.

    • Bonus #1: Doesn't interfere with other packages already installed (no dependency issues).
    • Bonus #2: The Docker images themselves pretty much never use Systemd, so you can often inspect the Dockerfile to see how the service is started without Systemd. For more information see the next option - "The manual way."
  • Option 3: "The 'manual' way"

    Edit: Bumped down notch from its former position as "Option 2", since Docker is probably a better alternative for many services.

    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 (from man 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 a tmpfs 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.

  • Option 4: Run Systemd as PID 1 in a PID namespace/container

    Finally, it's possible to get Systemd running under WSL2 (but not WSL1). This is a fairly advanced topic, although there are multiple scripts and projects that attempt to simplify it.

    Warnings: Systemd fundamentally changes many aspects of Ubuntu when started, including the way that X sockets, login, WSL Interop, temp files, and more! Due to the shared VM nature of WSL2, some of these changes can even impact other distributions you are using without Systemd.

    My personal recommendation is to either (a) make sure that you understand what is going on behind the scenes should you use one of these techniques, (b) don't do it!, or (c) at the very least, when asking questions about why something doesn't work, make sure to let people know that you are using a Systemd helper script under WSL (and which one).

    With that out of the way ...

    Let's start with some of the more popular projects to enable Systemd in WSL:

    I don't personally run any of them on a regular basis, 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:

    1. 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.

    2. 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 that systemd is running as PID 1 in that namespace.

      At this point, you should be able to run systemctl.

    3. And after proving to yourself that it's possible, I recommend exiting all WSL instances completely, then doing wsl --shutdown. 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.

  • 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 of systemctl with Systemd units. You can see these by using ls /etc/init.d/.

    So, for example, you can start ssh with sudo service ssh start, and it will run the /etc/init.d/ssh script with the start 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 the service command for them as well.

  • Option 2: Docker

    Many packages/services are available as Docker images. Docker runs great under Ubuntu on WSL2 (specifically WSL2; it will not run on WSL1). If there's not a SysVinit "service" script for the service you are trying to start, there may very well be a Docker image available that runs in a containerized environment.

    Example: Elasticsearch, as in this question and my answer.

    • Bonus #1: Doesn't interfere with other packages already installed (no dependency issues).
    • Bonus #2: The Docker images themselves pretty much never use Systemd, so you can often inspect the Dockerfile to see how the service is started without Systemd. For more information see the next option - "The manual way."
  • Option 3: "The 'manual' way"

    Edit: Bumped down notch from its former position as "Option 2", since Docker is probably a better alternative for many services.

    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 (from man 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 a tmpfs 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.

  • Option 4: Run Systemd as PID 1 in a PID namespace/container

    Finally, it's possible to get Systemd running under WSL2 (but not WSL1). This is a fairly advanced topic, although there are multiple scripts and projects that attempt to simplify it.

    Warnings: Systemd fundamentally changes many aspects of Ubuntu when started, including the way that X sockets, login, WSL Interop, temp files, and more! Due to the shared VM nature of WSL2, some of these changes can even impact other distributions you are using without Systemd.

    My personal recommendation is to either (a) make sure that you understand what is going on behind the scenes should you use one of these techniques, (b) don't do it!, or (c) at the very least, when asking questions about why something doesn't work, make sure to let people know that you are using a Systemd helper script under WSL (and which one).

    With that out of the way ...

    Let's start with some of the more popular projects to enable Systemd in WSL:

    I don't personally run any of them on a regular basis, 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:

    1. 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.

    2. 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 that systemd is running as PID 1 in that namespace.

      At this point, you should be able to run systemctl.

    3. And after proving to yourself that it's possible, I recommend exiting all WSL instances completely, then doing wsl --shutdown. 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.

  • 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 of systemctl with Systemd units. You can see these by using ls /etc/init.d/.

    So, for example, you can start ssh with sudo service ssh start, and it will run the /etc/init.d/ssh script with the start 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 the service command for them as well.

    To autostart services (a la systemctl enable) at startup, see this answer on Super User for how to do this with /etc/wsl.conf.

  • Option 2: Docker

    Many packages/services are available as Docker images. Docker runs great under Ubuntu on WSL2 (specifically WSL2; it will not run on WSL1). If there's not a SysVinit "service" script for the service you are trying to start, there may very well be a Docker image available that runs in a containerized environment.

    Example: Elasticsearch, as in this question and my answer.

    • Bonus #1: Doesn't interfere with other packages already installed (no dependency issues).
    • Bonus #2: The Docker images themselves pretty much never use Systemd, so you can often inspect the Dockerfile to see how the service is started without Systemd. For more information see the next option - "The manual way."
  • Option 3: "The 'manual' way"

    Edit: Bumped down notch from its former position as "Option 2", since Docker is probably a better alternative for many services.

    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 (from man 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 a tmpfs 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.

  • Option 4: Run Systemd as PID 1 in a PID namespace/container

    Finally, it's possible to get Systemd running under WSL2 (but not WSL1). This is a fairly advanced topic, although there are multiple scripts and projects that attempt to simplify it.

    Warnings: Systemd fundamentally changes many aspects of Ubuntu when started, including the way that X sockets, login, WSL Interop, temp files, and more! Due to the shared VM nature of WSL2, some of these changes can even impact other distributions you are using without Systemd.

    My personal recommendation is to either (a) make sure that you understand what is going on behind the scenes should you use one of these techniques, (b) don't do it!, or (c) at the very least, when asking questions about why something doesn't work, make sure to let people know that you are using a Systemd helper script under WSL (and which one).

    With that out of the way ...

    Let's start with some of the more popular projects to enable Systemd in WSL:

    I don't personally run any of them on a regular basis, 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:

    1. 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.

    2. 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 that systemd is running as PID 1 in that namespace.

      At this point, you should be able to run systemctl.

    3. And after proving to yourself that it's possible, I recommend exiting all WSL instances completely, then doing wsl --shutdown. 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.

Small tweak
Source Link
NotTheDr01ds

systemctl is most often used to start services under Ubuntu. For older releases that don't support Systemd (or if you just choose not to enable it), there are still several alternatives that might work in place of the systemctl command.

systemctl is most often used to start services under Ubuntu. For older releases that don't support Systemd, there are still several alternatives that might work in place of the systemctl command.

systemctl is most often used to start services under Ubuntu. For older releases that don't support Systemd (or if you just choose not to enable it), there are still several alternatives that might work in place of the systemctl command.

Updated again for WSL 1.0.0 - Consolidated the other answer as well, and hopefully tightened it up some in the process
Source Link
NotTheDr01ds
Loading
Trying to do a better job of pointing people to the other answer
Source Link
NotTheDr01ds
Loading
Pointer to new answer
Source Link
NotTheDr01ds
Loading
Moving new information to a separate answer
Source Link
NotTheDr01ds
Loading
No new info - Just changed order of answer to highlight the solution that people keep reposting as new, but duplicaate answers ;-)
Source Link
NotTheDr01ds
Loading
added 106 characters in body
Source Link
NotTheDr01ds
Loading
Updated based on new WSL release today
Source Link
NotTheDr01ds
Loading
Mainly updated to include Docker as an alternative option. Other tweaks while I was editing.
Source Link
NotTheDr01ds
Loading
Added some Snap and Gnome context
Source Link
NotTheDr01ds
Loading
Was missing some indentation on a list. Changed it to a numbered list anyway, since it was chronological. Also changed `wsl --terminate <distro>` to `wsl --shutdown` since the Systemd changes impact *all* distributions.
Source Link
NotTheDr01ds
Loading
Added footnote on apps that may just not run without Systemd
Source Link
NotTheDr01ds
Loading
Clarify that Systemd can only be made to run on WSL2, not WSL1
Source Link
NotTheDr01ds
Loading
Fixed a bulleted list that was indented too far, and thus toast.
Source Link
NotTheDr01ds
Loading
added 2322 characters in body
Source Link
NotTheDr01ds
Loading
Source Link
NotTheDr01ds
Loading