autossh for a persistent ssh tunnel

My Internet in Grass Valley is newly fast, but my ISP’s NAT setup  means I have no way of initiating connections from outside into my home network. Nice for security, awkward for hackiness. (They do offer a DMZ configuration but when I had them enable it on the previous link it never worked and broke traceroute, so I’m not asking this time.)

Instead I’ve set up a persistent ssh tunnel so that a port on my Internet server is always forwarded through to the ssh port on my Linux server in the house. That way I can ssh in remotely through the tunnel.

The only novel part of this is autossh, which is a wrapper for ssh that takes care of restarting the ssh tunnel if something goes wrong. autossh logs to syslog and has some configuration environment variables, none of which I needed to alter. It monitors for the tunnel dying and also periodically sends traffic through to make sure the tunnel is still working. ssh also has a keepalive mechanism it’s probably wise to use.

I mostly followed this guide for setting it up. Except for the Upstart config; after spending 30 minutes tearing my hair out I remembered I hate upstart and a good ol’ BSD 4.2 rc.local script would do just fine. Also I set stuff up to run as a separate user, and made an ssh config, so really it ended up being quite different. Steps:

  1. create a new “autossh” user on both machines with a shell of /bin/false
  2. set up ssh keys without passwords for this user, so that my house computer can log into my Internet server without any passwords
  3. Set up an ssh config for the tunnel for the autossh user at home.
    Host tunnel
      ServerAliveInterval 60
  4. Test that a basic manual ssh tunnel works as user autossh, without a password. This is important; first time you have to accept the ssh key manually!
    home$ autossh -N -R 2200:localhost:22 server
  5. Put the command to launch the tunnel in /etc/rc.local on the home computer
    su autossh -s /bin/bash -c 'autossh -fN -R 2200:localhost:22 tunnel'

Note the “-s” flag to su in the init script. Without that it runs as the /bin/false shell the user has which not only doesn’t work, but doesn’t give any useful error output.