I have a script which establishes a reverse tunnel on an endpoint HostB. It looks like this:

cat tun.sh

#!/usr/bin/env bash

# Test code
/usr/bin/ssh -V 1> /home/userA/bin/tun.stdout 2> /home/userA/bin/tun.stderr

# Establish tunnel
createTunnel() {
    /usr/bin/ssh -R *:19999:localhost:22 userB@hostB

# Do nothing if tunnel is already established
/usr/bin/ssh -p 19999 userA@hostB true
if [[ $? -ne 0 ]]; then

when I run it manually like ./tun.sh it works, and I can see on HostB, that userA is logged in. If I run it again on HostA but from another console, it works as expected - it does not launch a second tunnel.

Everything so far is good.

I now edit my crontab to look like this:

crontab -l

# m h  dom mon dow   command
*/1 *   *   *   *   /home/userA/bin/tun.sh

It runs the script every minut. This should be fine, since the script terminates if the tunnel is already established.

However, now userA does not get logged in as when I run it manually from the console.

The test code in the top of the script confirms that the script is being called, and that it has permission to execute /usr/bin/ssh:

~/bin$ ls

tun.sh  tun.stderr  tun.stdout

~/bin$ cat tun.stderr

OpenSSH_5.3p1 Debian-3ubuntu7, OpenSSL 0.9.8k 25 Mar 2009

~/bin$ cat tun.stdout


For some reason -V writes to stderr and not stdout, but that is a detail. The main point is here that the script is being executed every minute.

My question is: why is the SSH tunnel not established?

  • I see an unquoted globbing character in /usr/bin/ssh -R *:19999:localhost:22 userB@hostB... Need not be the problem but that is a quite direct way to shell hell. May 14 '14 at 13:03
  • 1
    Does your SSH key have a password? May 14 '14 at 13:03
  • 1
    if you’re using ssh-agent, you need the cron job to have the evironment variables to let it find the ssh-agent process May 14 '14 at 13:04
  • ssh-agent seems to be the right pointer. I will post an answer when I have set this up correctly.
    – Einar
    May 14 '14 at 14:45

Thanks to @Andrew for pointing to ssh-agent. As far as I can see, if one wants to be able to establish the tunnel without having to enter a password each time, the password must be stored or removed. I chose to remove it. For the record, here are some clean-ups based on the comments I got:

#!/usr/bin/env bash

# Establish tunnel
createTunnel() {
    /usr/bin/ssh -i /home/laptopuser/.ssh/id_rsa_tunnel -R 2200:localhost:22 vpsuser@vps.com

# Do nothing if tunnel is already established
/usr/bin/ssh -i /home/user/laptopuser/.ssh/id_rsa_tunnel -p 2200 laptopuser@vps.com true
if [[ $? -ne 0 ]]; then


# m h  dom mon dow   command
*/1 *   *   *   *   /home/laptopuser/bin/establishTunnel.sh

copy your tunnel id to the vps:

ssh-copy-id -i /home/user/laptopuser/.ssh/id_rsa_tunnel vps.com

wait until tunnel is running (see sudo watch grep CRON /var/log/syslog) and copy your normal id if you have not already got in ~/.ssh/authorized_keys

ssh-copy-id vps.com -p 2200

Ideally the tunnel would run as dedicated user both on the vps and the laptop.


I had a similar problem - ssh tunnel works if executed from script but not from crontab. ssh looks for keys and known_hosts in $HOME/.ssh. If you're running the script from bash under user tom, $HOME will be /home/tom. If the script is run from crontab the user will be root and $HOME will be /home/root (or undefined).

Solution: Define HOME in your script for the user that has the keys.

  • 1
    The user that a cron job is run as depends on whose crontab the job is specified in. Cron jobs belonging to ordinary users are not run by root. That would be a severe security risk.
    – Kusalananda
    Feb 28 '18 at 14:40

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

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