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:
- create a new “autossh” user on both machines with a shell of /bin/false
- set up ssh keys without passwords for this user, so that my house computer can log into my Internet server without any passwords
- Set up an ssh config for the tunnel for the autossh user at home.
Host tunnel ServerAliveInterval 60 HostName example.com
- 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
- 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.