31

I want to launch an SSH server on Linux subsystem (Bash on Ubuntu on Windows) at windows startup. The problem is that all Linux processes are terminated when Bash window is closed.

Is there a way to make Linux process run permanently in background without bash window?

0

6 Answers 6

30

Found a tutorial for that by aseering:

This was originally discussed and sorted out by github users imjakey, fpqc, qris, therealkenc, Manouchehri, and aseering (myself) here:

https://github.com/Microsoft/BashOnWindows/issues/612

Note that running sshd has security implications. Until WSL's security model has had longer to bake, you should assume that anyone who can ssh into your Windows box has permission to perform any command as the Windows user running sshd, regardless of Linux-level permissions. (Permissions are probably more restrictive than that in practice, but WSL's initial security model is not intended to be very sophisticated.)

Attempting to aggregate the instructions from github:

  • Generate SSH host keys by running sudo dpkg-reconfigure openssh-server in a bash shell
  • Run sudo nano /etc/ssh/sshd_config; edit the UsePrivilegeSeparation yes line to read UsePrivilegeSeparation no. (This is necessary because UsePrivilegeSeparation uses the chroot() syscall, which WSL doesn't currently support.)
  • While still editing /etc/ssh/sshd_config, you may choose to change PasswordAuthentication no to PasswordAuthentication yes. Otherwise you will have to set up SSH keys.
  • Save /etc/ssh/sshd_config and exit.
  • Run sudo visudo to edit the sudoers file. Add the line

    $USER ALL = (root) NOPASSWD: /usr/sbin/sshd -D
    

    replacing "$USER" with your Linux username. Save and exit. If visudo complains that your changes are invalid, fix them until it reports that they are valid; otherwise you can break sudo on your system!

  • On the Windows side, edit the Windows firewall (and any third-party firewalls that you might be running) to allow incoming traffic on port 22. Because this isn't a super-secure setup, I recommend only allowing incoming traffic from home (private) and domain networks, not from the public Internet.
  • Create a text file autostartssh.vbs in Windows containing the following:

    set ws=wscript.createobject("wscript.shell")
    ws.run "C:\Windows\System32\bash.exe -c 'sudo /usr/sbin/sshd -D'",0
    
    • Double-click on the script. It should start sshd; you should be able to ssh into your Windows machine.
    • Open Windows's Task Scheduler. Add a task that runs autostartssh.vbs on system boot. Use wscript.exe as the command to run and the VBS script location as the parameter.

And that's it -- your Windows computer should be running a Linux openssh server!

5
  • The VBS script didn't do anything for me. sshd isn't showing up in resource monitor Network tab.
    – megamaiku
    Apr 13, 2017 at 22:25
  • I wrote a a process dispatcher github.com/131/dispatcher that 'll allows you to spawn bash with no windows.
    – 131
    Nov 1, 2017 at 15:56
  • 1
    @megamaiku: I had the same problem. Turns out the little snipped to run sshd got stuck on the (invisible) password prompt because I didn't do the "visudo" part right. At first I added the NOPASSWD line somewhere in the middle of the sudoers file. It worked once I moved it to the bottom!
    – ltjax
    Dec 3, 2017 at 12:21
  • 1
    It's currently working with UsePrivilegeSeparation = yes , except that one needs to also run sudo /bin/mkdir -p /var/run/sshd (to create the privilege separation directories) before starting sshd. Does WLS now support chroot(), is there a workaround in place in the openssh source, or is the = No setting more of a safety recommendation? Also, the windows task seems to only work for me if my user is logged in.
    – init_js
    Dec 11, 2017 at 23:12
  • This worked excellently. I would suggest, to make things easier, move the port SSH is listening on, e.g. 3322, something random. Comment out the line in /etc/ssh/sshd_config that reads Port 22 and switch to Port 8822. One reason for this is Windows running some sort of SSH process on 22. I've seen suggestions saying there's no problem with disabling that, but I found it easiest to just switch the WSL SSH port.
    – knickum
    Apr 6, 2018 at 14:48
22
  1. Create a file named wsl_setup.bat and add content as follow

    wsl -u root -e sudo service ssh start
    wsl -u root -e sudo service nginx start
    
  2. Add wsl_setup.bat file to windows startup folder windows-10-change-startup-apps

  3. Restart and log in your windows account (yes, you need to log in)

4
  • This is best answer, We can change which distrib we want to run the command on by adding -d Debain where Debain can be replaced by any name of distro installed, which one can obtain by running wsl -l. Jul 13, 2020 at 15:35
  • Important note: Do not name the .bat file like the command you are using inside (eg. wsl.bat)
    – kanlukasz
    Dec 3, 2020 at 18:35
  • 1
    Awesome answer! Had to lookup (thanks for the link) how to get to the startup folder. TLDR; is WIN+R then shell:startup. Pretty easy.
    – PhilT
    Feb 17, 2021 at 14:47
  • While a good answer for the general use case, this honestly doesn't address the original question. The OP asked how to do this at Windows boot, not login. The accepted answer (using wscript), as well as @Nom's suggestion to autologin, are ways to do this. Nov 2, 2021 at 21:15
4

I've needed to do the same thing.

Here's how to boot the Ubuntu Linux subsystem with all of cron's services upon the Windows boot & provide a means to 'reboot' the Linux subsystem.

I'm successfully hosting the openssh-server, nginx & mariadb database on our server.

Install Linux Subsystem

  • Open Powershell as Administrator
  • Paste:

    Enable-WindowsOptionalFeature -Online -FeatureName Microsoft-Windows-Subsystem-Linux
    
  • Install Ubuntu from Windows Store.

Remove sudo password prompt (required)

  • Open bash (Linux Subsystem installs this)
  • Paste:

    sudo sed -i "s/%sudo.*/%sudo ALL=(ALL:ALL) NOPASSWD:ALL/g" /etc/sudoers
    

Enable SSH password login (optional)

  • Open bash
  • Paste:

    sudo sed -i '/StrictModes yes/c\StrictModes no' /etc/ssh/sshd_config
    sudo sed -i '/ChallengeResponseAuthentication/c\ChallengeResponseAuthentication no' /etc/ssh/sshd_config
    sudo sed -i '/PasswordAuthentication/c\PasswordAuthentication yes' /etc/ssh/sshd_config
    

Windows autologin on start (required if you have a password or RDP in)

  • Open netplwiz
  • Untick 'Users must enter a username and password...'
  • Open regedit as Administrator
  • Browse to

    HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Winlogon
    
  • Create a new string DefaultPassword and write the user's password as value.

Run bash/cron loop on start

  • Create a file called linux.bat in shell:startup
  • Paste:

    C:\Windows\System32\bash.exe -c 'while [ true ]; do sudo /usr/sbin/cron -f; done'
    

Add apps/services to startup on cron

  • Open bash
  • sudo crontab -e
  • Select nano (or any editor you know how to save in)
  • Append startup apps such as openssh-server, nginx, mysql, php:

    PATH=/usr/local/sbin:/usr/local/bin:/sbin:/bin:/usr/sbin:/usr/bin
    @reboot . $HOME/.profile; /usr/sbin/sshd -D
    #@reboot . $HOME/.profile; service php7.1-fpm start # Uncomment for php7.1 fpm
    #@reboot . $HOME/.profile; service mysql start # Uncomment for mysql/mariadb
    #@reboot . $HOME/.profile; service nginx start # Uncomment for nginx
    
  • Save and exit: ctrlx, then press y and enter.

Reboot the Linux subsystem without rebooting Windows

  • Open bash or SSH in

    sudo service ssh restart
    
  • This will close the current instance and create a new one applying cron.

Extra - Install PHP 7.1 (not quite as straight forward)

  • Run the commands below for a pretty standard setup:

    mkdir /run/php && chmod -R 777 /run/php
    sudo add-apt-repository ppa:ondrej/php && sudo apt update
    PHPV=7.1 && sudo apt install --allow-unauthenticated -y php${PHPV}-fpm php${PHPV}-gd php${PHPV}-json php${PHPV}-mysqlnd php${PHPV}-curl php${PHPV}-intl php${PHPV}-mcrypt php${PHPV}-imagick php${PHPV}-zip php${PHPV}-xml php${PHPV}-mbstring
    
  • Run the command below for an 'OwnCloud' setup:

    PHPV=7.1 && apt install --allow-unauthenticated -y php${PHPV}-redis redis-server php${PHPV}-ldap php${PHPV}-smbclient
    

Extra - Install nginx webserver

  • Run the commands below for a base setup with PHP7.1:

    sudo add-apt-repository ppa:nginx/stable
    sudo apt update && sudo apt -y install nginx
    sudo sed -i 's:access_log /var/log/nginx/access.log;:access_log off;:g' /etc/nginx/nginx.conf
    sudo sed -i '/index index.html/c\\tindex index.html index.php index.htm index.nginx-debian.html;' /etc/nginx/sites-available/default
    STR='}\n\n\tlocation ~ \.php$ {\n\t\tinclude snippets\/fastcgi-php.conf;\n\t\tfastcgi_pass unix:\/var\/run\/php\/php7.1-fpm.sock;\n\t}'
    sudo sed -i "0,/}/s//$STR\n/" /etc/nginx/sites-available/default
    sudo service nginx restart
    

Extra - Install mariadb's mysql database

  • Run the commands below for a mysql database server:

    RELEASE=`lsb_release -a | tail -1 | cut -f2`
    sudo apt install software-properties-common
    sudo apt-key adv --recv-keys --keyserver hkp://keyserver.ubuntu.com:80 0xF1656F24C74CD1D8
    sudo add-apt-repository "deb [arch=i386,amd64,ppc64el] https://mirrors.evowise.com/mariadb/repo/10.3/ubuntu $RELEASE main"
    sudo apt update && sudo apt --allow-unauthenticated -y install mariadb-server
    
  • When prompted, set a root database user password.

2
  • That is very clever! and precise instructions, thanks. Is there a way to avoid skipping "sudo" password entirely?
    – greg
    Apr 13, 2018 at 9:26
  • I don't recommend using the Linux subsystem anymore. The app compatibility sucks, it's unstable and the tools don't all work as well as they could - bash integration, etc. Instead use msys2, it provides you with a great bash shell and will allow you to install a lot of apps via its pacman package manager - Best of all, all of the apps are .exe's. All you need to do is add the bin directories to your environment variables in Windows. I use linux commands in windows and vice versa now. All of my Windows scripting is done in bash.
    – Nom
    Apr 28, 2018 at 4:24
3

@Poma and @Hintron answers are great.

I would like to extend description of last point how to add ssh task in Windows Task Scheduler as it requires switching some options:

  • Run "Task Scheduler". On the left list select "Task Scheduler (Local)", then go to "Action" menu and "Create Task".
  • General tab:
    • Name: "ssh"
    • Select "Run whether user is logged on or not"
  • Triggers tab:
    • New
      • Begin the task: "At startup"
  • Actions tab:
    • New
      • Program/script: C:\Windows\System32\bash.exe
      • Add arguments (optional): -c "sudo /usr/sbin/service ssh start"
  • Conditions:
    • Unselect "Start the task only if the computer is on AC power
  • Settings
    • Unselect "Stop the task if it runs longer than

It is used direct bash invocation. There is no need to wrap it in vbs or powershell scripts.

I use service command for reasons that @Hintron explained. Additionally direct sshd invocation gives error

Missing privilege separation directory: /var/run/sshd

In such case it should be added this entry by sudo visudo command

ALL ALL = (root) NOPASSWD: /usr/sbin/service ssh *

Also notice that here all users (first column) can start or stop sshd. If your are only one user of this Windows machine, then it should be fine.

1

@poma 's answer is very good, and is what my answer is based off of. I want to add some improvements to it, though:

  • Use service instead of calling sshd directly: 'sudo service ssh start' instead of 'sudo /usr/sbin/sshd -D'. That way, even if you call the script multiple times, there will only be at most one sshd process. Also, it's easy to kill it with another script that runs 'sudo service ssh stop'. In the sudoers file, you simply need to replace /usr/sbin/sshd -D with /usr/sbin/service.
  • If you are set on calling sshd directly, get rid of the -D option, because that will put a process in the foreground indefinitely. If you don't believe me, just do top and you will see an init and a sudo process for each time you called the script. Don't forget to remove the -D option in the sudoers file as well!
  • Use PowerShell instead of vbs! Create a file called autostartsshd.ps1 and paste in the following: bash -c 'sudo service ssh start'. To execute the script, right click it and click Run with PowerShell.

Another stack overflow question has similar steps: https://superuser.com/a/1114162/182590

Hope that helps someone :)

2
  • Are you sure this will work? Running sshd in the foreground was intentional to keep bash session open (there will be no problems with multiple instances because duplicates will fail to start). If you just run sudo service ssh start and then close bash it will kill ssh daemon. At least that's what it did at the moment of writing my guide.
    – Poma
    May 28, 2018 at 17:34
  • @Poma With the latest update to Windows 10, Linux applications can now run in the background, so I think this should work fine. May 29, 2018 at 14:04
0

put bash -c "echo [password] | service ssh start" in Windows startup script, and use your own sudo password to substitute [password]

1
  • You can't just pipe a password to a sudo prompt (not that your command even includes the necessary sudo keyword that your sentence implies). This just doesn't work. Not that you should ever store your password in plaintext anyways!
    – adam_0
    Sep 17, 2019 at 15:58

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge that you have read and understand our privacy policy and code of conduct.

Not the answer you're looking for? Browse other questions tagged or ask your own question.