sshd and cron on Windows Using Cygwin

For those working on windows who miss their linux command line friends, there is hope. Cygwin is a great tool to allow you to use your favourite linux tools on your windows machine. Installing and running cygwin is very simple, this guide presumes that you are familiar with linux and running cygwin shells. This guide focuses on running linux daemons for ssh and cron. The following instructions work on Windows 7 so your milage may vary on different versions.

Note: on Windows Vista or Windows 7, you need to run as administrator when launching the cygwin shell to allow the registry changes required in some of the steps below. You can configure cygwin to always launch with admin privileges if you wish.


The following packages are required:

  • cygrunsrv
  • openssh
  • cron
  • nano or vim or another editor

Ensure that the $EDITOR environment property is set for your preferred editor, ideally in one of the profile files (e.g. .bashrc or .bash_profile).

Windows Security

As outlined in windows security in cygwin, there are 3 methods to allow the user context to switch without passwords. The most appropriate choice is to use the LSA authentication package by running the cyglsa-config script. Simply run it and answer the questions posed. The following is a typical log output:

$ cyglsa-config

Warning: Registering the Cygwin LSA authentication package requires
administrator privileges!  You also have to reboot the machine to
activate the change.

Are you sure you want to continue? (yes/no) yes

Cygwin LSA authentication package registered.

Activating Cygwin's LSA authentication package requires to reboot.
Do you want to do this immediately? (yes/no) no

Now reboot when its safe.

Alternatively, passwd -R can be used to install a given users password into the registry but this may pose a security risk in some environments.


Cygwin takes all the pain out of setting up sshd by providing a setup script called ssh-host-config. Simply run it and answer the questions posed. The following is a typical log output:

$ ssh-host-config
*** Query: Overwrite existing /etc/ssh_config file? (yes/no) yes
*** Info: Creating default /etc/ssh_config file
*** Query: Overwrite existing /etc/sshd_config file? (yes/no) yes
*** Info: Creating default /etc/sshd_config file
*** Info: Privilege separation is set to yes by default since OpenSSH 3.3.
*** Info: However, this requires a non-privileged account called 'sshd'.
*** Info: For more info on privilege separation read /usr/share/doc/openssh/README.privsep.
*** Query: Should privilege separation be used? (yes/no) yes
*** Info: Note that creating a new user requires that the current account have
*** Info: Administrator privileges.  Should this script attempt to create a
*** Query: new local account 'sshd'? (yes/no) yes
*** Info: Updating /etc/sshd_config file

*** Warning: The following functions require administrator privileges!

*** Query: Do you want to install sshd as a service?
*** Query: (Say "no" if it is already installed as a service) (yes/no) yes
*** Query: Enter the value of CYGWIN for the daemon: [] ntsec tty
*** Info: On Windows Server 2003, Windows Vista, and above, the
*** Info: SYSTEM account cannot setuid to other users -- a capability
*** Info: sshd requires.  You need to have or to create a privileged
*** Info: account.  This script will help you do so.

*** Info: You appear to be running Windows 2003 Server or later.  On 2003
*** Info: and later systems, it's not possible to use the LocalSystem
*** Info: account for services that can change the user id without an
*** Info: explicit password (such as passwordless logins [e.g. public key
*** Info: authentication] via sshd).

*** Info: If you want to enable that functionality, it's required to create
*** Info: a new account with special privileges (unless a similar account
*** Info: already exists). This account is then used to run these special
*** Info: servers.

*** Info: Note that creating a new user requires that the current account
*** Info: have Administrator privileges itself.

*** Info: No privileged account could be found.

*** Info: This script plans to use 'cyg_server'.
*** Info: 'cyg_server' will only be used by registered services.
*** Query: Do you want to use a different name? (yes/no) no
*** Query: Create new privileged user account 'cyg_server'? (yes/no) yes
*** Info: Please enter a password for new user cyg_server.  Please be sure
*** Info: that this password matches the password rules given on your system.
*** Info: Entering no password will exit the configuration.
*** Query: Please enter the password:
*** Query: Reenter:

*** Info: User 'cyg_server' has been created with password 'xxxxxxxx'.
*** Info: If you change the password, please remember also to change the
*** Info: password for the installed services which use (or will soon use)
*** Info: the 'cyg_server' account.

*** Info: Also keep in mind that the user 'cyg_server' needs read permissions
*** Info: on all users' relevant files for the services running as 'cyg_server'.
*** Info: In particular, for the sshd server all users' .ssh/authorized_keys
*** Info: files must have appropriate permissions to allow public key
*** Info: authentication. (Re-)running ssh-user-config for each user will set
*** Info: these permissions corrently. [Similary restrictions apply, for
*** Info: instance, for .rhosts files if the rshd server is running, etc].

*** Info: The sshd service has been installed under the 'cyg_server'
*** Info: account.  To start the service now, call `net start sshd' or
*** Info: `cygrunsrv -S sshd'.  Otherwise, it will start automatically
*** Info: after the next reboot.

*** Info: Host configuration finished. Have fun!

As the instructions state, the sshd service can be started using either net start sshd, cygrunsrv -S sshd or even using the services management console. Test the connection by sshing to localhost. If you experience any problems try running in verbose mode, e.g:

ssh localhost
ssh username@localhost
ssh -vvv username@machinename

Windows likes to title case usernames and allows spaces, therefore make sure the username is correct if this is the case, e.g. ssh John\ Smith@localhost.


Once again, Cygwin provides a script to install cron called cron-config. Simply run it and answer the questions posed. Even if using passwd -R or cyglsa package, answer no to install the service under the cyg_server user. The following is a typical log output:

$ cron-config
Do you want to install the cron daemon as a service? (yes/no) yes
Enter the value of CYGWIN for the daemon: [ ] ntsec

You must decide under what account the cron daemon will run.
If you are the only user on this machine, the daemon can run as yourself.
   This gives access to all network drives but only allows you as user.
To run multiple users, cron must change user context without knowing
  the passwords. There are three methods to do that, as explained in
If all the cron users have executed "passwd -R" (see man passwd),
  which provides access to network drives, or if you are using the
  cyglsa package, then cron should run under the local system account.
Otherwise you need to have or to create a privileged account.
  This script will help you do so.
Do you want the cron daemon to run as yourself? (yes/no) no

Were the passwords of all cron users saved with "passwd -R", or
are you using the cyglsa package ? (yes/no) no

Attempting to find or create a privileged user.
The following accounts were found: 'cyg_server' .
This script plans to use the name cyg_server for the new user,
which will only be able to run as a service.
Do you want to use another name (not an interactive account)? (yes/no) no

Please enter the password for user 'cyg_server':

Running cron_diagnose ...
WARNING: Your computer does not appear to have a cron table for username.
Please generate a cron table for username using 'crontab -e'

... no problem found.

Do you want to start the cron daemon as a service now? (yes/no) yes
OK. The cron daemon is now running.

In case of problem, examine the log file for cron,
/var/log/cron.log, and the Windows event log (using /usr/bin/cronevents)
for information about the problem cron is having.

Examine also any cron.log file in the HOME directory
(or the file specified in MAILTO) and cron related files in /tmp.

If you cannot fix the problem, then report it to
Please run the script /usr/bin/cronbug and ATTACH its output
(the file cronbug.txt) to your e-mail.

WARNING: PATH may be set differently under cron than in interactive shells.
         Names such as "find" and "date" may refer to Windows programs.

I prefer to reinstall the cron service so that it is similarly named to the sshd service. The following commands will remove the service and recreate it as desired:

cygrunsrv -R cron
cygrunsrv -I cron -d "CYGWIN cron" -u cyg_server -p /usr/sbin/cron -a -n

Like any service, the cron service can be started using either net start cron, cygrunsrv -S cron or even using the services management console.

Crontab entries can be made for a given user by logging in as that user and running crontab -e. This will use the $EDITOR environment variable to determine which editor to use, and will also validate the file afterwards. Essentially, using crontab creates a file named after the user in /var/cron/tabs with the correct permissions and ownership.

For example, run crontab -e and enter the following then save:

*/10 * * * * echo `date` > /home/username/test-crontab.txt

This will output the date every 10 minutes into the /home/username/test-crontab.txt file. Using the crontab command also informs cron to re-read the crontabs without having to restart the service. Note that it is a good idea to supply the PATH environment variable to ensure that the execution path is correct for any commands. HOME is set to the home of the user.

Cron also checks for files in the system directory /etc/cron.d. By default this does not exist in cygwin so run the following commands to set this up with the required permissions:

mkdir /etc/cron.d
chmod 754 /etc/cron.d

Additionally, any crontabs must be owned and only writable by SYSTEM. You can ensure that crontabs have the correct permissions and ownership by running the following (after creating the crontab):

chmod 644 /etc/cron.d/*
chown SYSTEM:SYSTEM /etc/cron.d/*

System crontabs differ slightly from normal crontabs in that the first argument after the time and date fields is the username of the user to execute the command. For example, create /etc/cron.d/example with the following contents:

PATH=/usr/bin:/usr/sbin:. HOME=/home/username */10 * * * * username echo date > /home/username/test-cron.d.txt

Other Considerations

Cron problems

If you are having problems then look at C:\tools\cygwin\usr\share\doc\Cygwin\cron-*.README

For example, you can install the service with some debug options for cron:

cygrunsrv -I cron -d "CYGWIN cron" -u cyg_server -p /usr/sbin/cron -a "-x sch,proc,pars,load,misc"

View the logs with something like:

cat /var/log/cron.log
cat /home/username/cron.log

There is lots of information in the man pages:

man crontab
man cron
man 5 crontab

Bash Prompt Here

This isn’t strictly part of this guide, but I think its so useful that I have to mention it. The chere package is a tool that creates a “bash prompt here” entry in windows explorer context menus. To install it simply run the following (with admin rights):

chere -i


Sometimes when updating cygwin there are modifications to major binaries that require services to be stopped and possibly kill any cygwin processes that are running to allow the update to overwrite the files. Simply restart the services after completion. If there are updates to the LSA then you will need a reboot also.

Registering users in passwd

Sometimes you need to register the user in passwd to allow ssh and cron to use the user. This can be acheived using mkpasswd.

Check if the user is already registered:

cat /etc/passwd

If the user is a domain account then run the following to add them:

mkpasswd -d domain_name -u domain_username >> /etc/passwd

If the user is a local account then run the following to add them:

mkpasswd -l -u local_username >> /etc/passwd


blog comments powered by Disqus
Fork me on GitHub