This is not a proper SSH VPN as described at http://www.debian-administration.org/articles/539 But if you are in the situation where you cannot use TUN/TAP modules such as on a Virtuozzo/OpenVZ based VPS and the hosting provider refuses to enable those modules for you then this is a way to be able to link back to internal services.
We will use SSH, SSH Keys for password-less authentication and AutoSSH to achieve a poor mans' (but secure!) VPN.
First lets generate some SSH keys. Password authentication is not appropriate because AutoSSH cannot use password authentication. We will also set permissions on the key. I am generating my keys on the VPS, and I going to have it connect back to the "office".
# ssh-keygen Generating public/private rsa key pair. Enter file in which to save the key (/root/.ssh/id_rsa): /root/.ssh/vps01 Enter passphrase (empty for no passphrase): Enter same passphrase again: Your identification has been saved in /root/.ssh/vps01. Your public key has been saved in /root/.ssh/vps01.pub. The key fingerprint is: a0:31:4a:49:5f:78:de:09:33:5e:f5:af:94:c8:aa:04 firstname.lastname@example.org # chmod 600 /root/.ssh/vps01
Keep the key file (/root/.ssh/vps01) safe! If somebody gets hold of it they can connect to your server without a password! I use a TrueCrypt protected USB key for keeping passwords and private keys.
Now to prep the SSH server. This is only needed on one of the servers. In your /etc/ssh/sshd_config make sure the following is uncommented
RSAAuthentication yes PubkeyAuthentication yes
Now place your public key on the remote server (from my point of view, the office server) and then add the public key to the SSH keyring. "User" should not be root (ideally) and it should be the user to which you want to be able to authenticate to without a password.
# sftp email@example.com > PUT /root/.ssh/vps01.pub > exit # ssh firstname.lastname@example.org # cat vps01.pub >> ~/.ssh/authorized_keys # rm vps01.pub # chmod 700 ~/.ssh # chmod 600 ~/.ssh/authorized_keys # exit
The SSH key section above needs to be reviewed! Google around yourself, there is a million write-ups on this.
Once the SSH connection can be established without the need of manually entering a password you are well on your way. Now all you have to do is establish a tunnel between the servers for the services you need. In my case I needed to tunnel LDAP so that I could slave LDAP server locally.
First, we just download and install AutoSSH. Apparently there is a package in the Debian repos, but I am on CentOS so I must compile it myself. Definitely the simplest program I have ever compiled and installed!
# #Check for the newest version - http://www.harding.motd.ca/autossh/. # wget http://www.harding.motd.ca/autossh/autossh-1.4b.tgz # tar xzvf autossh-1.4b.tgz # cd autossh-1.4b/ # yum install gcc # ./configure && make && make install
Now you can run autossh!
# I am tunnelling the remote server's LDAP to my Local (denoted by "-L") port 388. The remote server's SSH port is on 2389 and AutoSSH is using port 20000 as an echo server. autossh -f -M 20000 -N -L 388:localhost:389 email@example.com -p 2389
To test if this was working I can use Telnet on my local port 388. If it connects then it works!
# telnet localhost 388 Trying 127.0.0.1... Connected to localhost. Escape character is '^]'
Since I am on CentOS I will do it this way. On Debian based systems you may have to take a different approach - probably by putting a script in the /etc/rc.d directory.
This is a small script called "autosshd"
# chkconfig: 2345 90 10 # description: autosshd - This is an autostart script for AutoSSH to bring up our "VPN". autossh -f -M 20000 -N \ -L 388:localhost:389 \ # You can add another -L or -R line here to tunnel more ports! but follow by a \ firstname.lastname@example.org -p 238
Then you need to put your script into /etc/init.d and then run "chmod +x /etc/init.d/autosshd" and then run "chkconfig --add autosshd". This will read the first two lines of your script and add it to the system startup accordingly.
The best documentation on AutoSSH can be viewed by running "man autossh".
But for those who are too lazy to read much, basically you should provide a port for AutoSSH to send and receive data through to function as an "echo" so that AutoSSH can determine if the connection is working properly. This is referred to as the echo port for obvious reasons and in our case is port 20000 and technically also 20001.
The "-f" option is also useful in that it pushes the process into the background so that it does not block your shell, but beware because you will not see any debug output or prompt for password!
You can provide more options to AutoSSH by setting environment variables (you can put AUTOSSH_VARIABLE=whatever near the top of your startup script) so that you can specify normal SSH options more or less by just replacing the normal "ssh" with "autossh". If you put your options in-line they will be parsed out by AutoSSH before they are passed to SSH.
The main thing that you have to understand before you can start forwarding ports through SSH is that you can forward LOCAL ports and REMOTE ports. If you look at the SSH man page (run "man ssh") you will see that there is a -L option and a -R option. Think of these the following way.
-L Forward REMOTE port x to your LOCAL port x.
-R Forward LOCAL port x to your REMOTE port x.
So in my example I forwarded the remote port 389 (LDAP) to my local port 388. This means that it is pushing anything I put into my local port 388 over to the remote 389 and stuff can come back the other way too. If you are wondering "why 388 and not 389?" - this is because I want to run a local LDAP server on port 389 and you cannot have two servers on the same port! However if I just wanted to connect to LDAP over the Internet without having a local server I would forward it to my local port 389. If you were connecting your mail client to a mail server using SSH tunneling you would forward remote 25 and 143 directly to your local 25 and 143 for convenience.