In a previous article we talked about screen, that was used to setup reverse ssh tunnels on deployed infrastructure without the hassle of setting up port-forwarding on every modem thery are deployed behind. Today I will note down a better way to set this up, without screen, in a single crontab.
Without much further ado, the glorious crontab:
* * * * * ssh -q -f -N -R 8888:localhost:22 REMOTEUSER@remote.example.com -o "ExitOnForwardFailure yes" -o "ServerAliveInterval 15" -o "ServerAliveCountMax 2" 2>/dev/null
And on remote.example.com
to connect to the tunnel (as before):
su REMOTEUSER
ssh LOCALUSER@localhost -p 8888
Why does it work: first, we suppress messages (-q
, 2>/dev/null
so my /var/spool/mail/LOCALUSER
mail does not get uselessly populated after each network hiccup), we detach the ssh command (-f
), in batch-mode (-N
, no command issued on remote host), then we define the reverse tunnel (-R 8888:localhost:22
, redirect port 8888 on remote to port 22 on localhost), we connect as user REMOTEUSER
on remote.example.com (REMOTEUSER@remote.example.com
), and most importantly we set ExitOnForwardFailure yes
so the ssh tunnels exits if it is unable to create the forward tunnel (most notably if it is already set), we define another pair of failsafe so if the connection is cut it will exit after 30 seconds (ServerAliveInterval 15
and ServerAliveCountMax 2
, 15*2) of inactivity, so the tunnel could be recreated the next minute when the crontab is executed.
Addentum 2020-02-04: You should probably reduce sshd log verbosity (LogLevel
) on the remote server as it appends a new line every minute as the connection fails if already established with ExitOnForwardFailure
.
Maybe also/instead you could use flock
to define a lock file for the crontab, like this
* * * * * flock -w 0 /tmp/sshtunnel.lock ssh -q -f -N -R 8888:localhost:22 REMOTEUSER@remote.example.com -o "ExitOnForwardFailure yes" -o "ServerAliveInterval 15" -o "ServerAliveCountMax 2" 2>/dev/null