Here is my procedure for establishing a reverse ssh tunnel that maintains a persistent ssh connection (using autossh) through a firewall/router with no configuration needed on the target (host) machine. I use this to maintain an Ubuntu/Edubuntu LTSP server for a small school several hours from home. As long as the school’s internet connection is working, the target server is impervious to changes in network settings, even though neither the school nor the server’s IP addresses are static.
On boot-up, the target machine establishes an ssh tunnel to the remote computer (called ‘Home’ hereafter) from which I will be working. For additional security, this tunnel allows no execution on Home from the target computer. On Home, I can then connect via ssh to localhost on the specified port using the command at the end of the procedure below. Although I use this primarily for console work, this also works well using NoMachine NX (or FreeNX), an amazing remote desktop app that runs on ssh. These instructions are Ubuntu/Debian specific, but they should work with minor modifications on any Linux distro. This is designed to be cut-and-paste in case you are uncomfortable with a lot of command-line input. Don’t forget to take advantage of the auto-complete feature of the shell (tabbing completes commands or file paths; double-tab shows options where your input is ambiguous).
As always, very little of this is original with me. Credit goes to others who have posted the technical details in many forums and blogs. I’m only compiling them in a format that worked for me.
On the target/host machine:
ssh-keygen -t dsa
Output: (accept defaults, do NOT enter a passphrase):
Generating public/private dsa key pair.
Enter file in which to save the key (/home/user/.ssh/id_dsa):
Enter passphrase (empty for no passphrase):
Enter same passphrase again:
Your identification has been saved in /home/user/.ssh/id_dsa.
Your public key has been saved in /home/user/.ssh/id_dsa.pub.
The key fingerprint is:
a9:93:4e:89:22:f0:01:xx:xx:xx:xx:xx:xx:xx:xx:xx user@target
The key's randomart image is:
+--[ DSA 1024]----+
| |
| |
|. |
|.. . |
|... . S |
| |
|. |
| .o. o .. . E |
| ... . .o.. |
+-----------------+
List the contents of your .ssh directory to be sure everything is as expected.
ls -l ./.ssh/
Output should be similar to this. Note the permissions on id_dsa.
total 36
-rw------- 1 user user 673 2010-08-20 15:43 authorized_keys2
-rw------- 1 user user 668 2010-08-26 07:06 id_dsa
-rw-r--r-- 1 user user 604 2010-08-26 07:06 id_dsa.pub
Copy the id_dsa.pub (public key) to the Home computer
ssh-copy-id [email protected]
Output (enter your password on home when prompted):
[email protected]'s password:
Now try logging into the machine, with
ssh '[email protected]'
and check the authorized_keys file to make sure we haven’t added extra keys that you weren’t expecting.
cat ~/.ssh/authorized_keys
Install autossh on remote:
sudo apt-get install autossh
Set up the script:
sudo mkdir /etc/tunnel
sudo touch /etc/tunnel/tunnel.sh
sudo cp .ssh/id_dsa /etc/tunnel/
Make sure permissions are tight:
sudo chmod -R 700 /etc/tunnel
sudo chmod 600 /etc/tunnel/id_dsa
Use the text editor of your choice; if you use Gnome/Gedit, run from Alt+F2:
gksu gedit /etc/tunnel/tunnel.sh
If you use KDE/Kate:
kdesudo kate /etc/tunnel/tunnel.sh
I use vim:
sudo vim /etc/tunnel/tunnel.sh
Now insert this script into tunnel.sh, obviously changing ‘Home’ to the name of the computer you will be using to work on the target machine ‘user’ to your user name. I ran this on a LAN before deploying the server (Did you know you can access a linux machine on your LAN using [hostname].local?):
#!/bin/bash
set +e
SSH_OPTIONS=" -i /etc/tunnel/id_dsa"
# Always assume initial connection will be successful
export AUTOSSH_GATETIME=0
# Disable echo service, relying on SSH exiting itself
export AUTOSSH_PORT=0
#to test, use (check out man ssh for explanation of options:
autossh -vv -- $SSH_OPTIONS -o 'ControlPath none' -R 10101:localhost:22 [email protected] -N > /var/user_sshlog.out 2> /var/user_ssh_error.out &
#once proven, use (and rem out previous command):
#autossh -f -- $SSH_OPTIONS -o 'ControlPath none' -R 10101:localhost:22 [email protected] -N 2> /var/user_ssh_error.out
NOTE: the logs are a Big Deal! With autossh or ssh set to verbose output (-vv), you can glean an awful lot of info from the log.
Assign script to run on start-up in /etc/rc.local:
sudo vim /etc/rc.local
Append this at the end of your rc.local:
#Delay scipt in case the network needs more time to start running. Adjust as necessary.
sleep 10
#Start autossh script, output to log
/etc/tunnel/tunnel.sh > /var/user_tunnel.log 2>&1
echo autossh to Home.local started
exit 0
[Note(!): Make sure you have logged in to Home from Target as root before trying to run script (to get past the authentication question):]
$$ ssh [email protected]
Output:
The authenticity of host 'Home.local (192.168.1.103)' can't be established.
RSA key fingerprint is f1:e9:5a:ea:58:xx:xx:xx:xx:xx:xx:xx:xx:xx:xx:6a.
Are you sure you want to continue connecting (yes/no)?
To test functionality without time-consuming reboots use:
sudo /etc/init.d/rc.local start
If you want to try again, make sure you kill all running autossh processes:
sudo killall autossh
Sometimes you may have to use:
sudo killall -9 autossh
Check your logs if you have problems:
cat /var/user_tunnel.log
or
cat /var/user_ssh_error.out
Now for the acid test. Login from Home
ssh -p 10101 user@localhost
If it works, you're done (unless you need to change the address in your tunnel.sh when you move the target from your LAN to the off-site location).
For additional testing of the script from a user file before committing it to /etc/rc.local, try this:
cat /etc/tunnel/tunnel.sh >> ~/tunnel.sh
chmod 700 tunnel.sh
and modify the script, commands, and log paths as appropriate.
If your Home is behind a NAT, set port forwarding appropriately.
To use NX, configure your session similarly to this:
If you see typos or errors in strategy here, I'd be obliged if you would leave comments accordingly.
Hi!
Thank you for the solution, but…
I think you could make good use of the html pre tag around the code blocks, or the wordpress plugin WP-Syntax (http://wordpress.org/extend/plugins/wp-syntax/).
It helps to format the code much more readable.
Have a nice day,
kms
Sorry for the delayed reply. I really should look into the syntax thing…when I have time. Thanks for the heads up.
Hey there, super glad to have found this as I’m thinking of setting something like this up for work. I’m considering doing this with a bunch of laptop nodes all connecting to a linux server. What has your experience been with the stability of autossh as a solution?
Also, supposing I had a bunch of nodes that may or may not be online at a given time, any thoughts on how to keep track of which nodes are actually online and ssh’d into my server?
Thanks for the great little tutorial, it’s a confidence booster to see that someone else is doing it already.
Thanks for the comment; I’m glad if you found this useful. Regarding your questions (if I’m not way too late to be helpful), I don’t think any of the connection stability issues that I had could be traced to autossh, but I can’t say for sure. I never did use this heavily, so you may soon have more data to help you than I have.
I don’t really remember how to track ssh connections, but you can use the “w” command to find out who is logged in, and what they are doing, along with some other stats. Of course, this isn’t anything graphical or auto-updating.
Best wishes
-M0 can replace AUTOSSH_PORT and I didn’t find I needed AUTOSSH_GATETIME why do you declare it? Surely with -M0 ssh will time out the connection eventually then exit at which point autossh will try again?
This is a case of where I simply took somebody else’s template, and it worked for me, so I didn’t bother tweaking it. But I agree that -M0 can replace AUTOSSH_PORT=0. I suppose the value of the latter is that it’s there if somebody wants to specify a port.
From the man page:
I might not need AUTOSSH_GATETIME either; I haven’t tried it without. I do want this to work without a hitch on an unattended reboot, so maybe it’s safer?
Anyway, thanks for your research.
thanks for the insight on autossh and supplying the remote port for ssh-copy-id
Pingback: SSH Tunnel on startup
Thanks very much! This helped me quite a bit.
Thanks! Now I am able to administer my parents ubuntu behind NAT 🙂
Pingback: Use Amazon EC2 and ssh reverse tunneling to connect computers behind firewall or NAT | juntx
Wonderful guide!
I’ve been looking at several other before this one, and as a linux beginner.. without much luck.
Your guide is by far the best one out there at the moment!
Thank you very much.
Kind regards,
Kristoffer
Thank you, I am planning to implement this to offer web services to family members 🙂
Similar guide is here: http://internetlifeforum.com/linux-forums/6657-way-access-administrate-any-home-computer-remotely-via-internet-via-ssh-proxy/
Thanks for the lead. Currently the link is down; any update to that would be helpful to future users.