Blog tvlooy

SSH VPN to your home network

Linux, OpenSSH | June 02, 2012

This is the first time I used OpenSSH as a VPN. Like always, it just works.

Setup

In the example below, I am on a corporate network with my laptop. The server on my own network runs an SSH server. The firewall on my network forwards traffic from port 80 to the server’s port 22. I want to be able to access my own servers from an external location.

Smart firewalls will probably see that it’s not HTTP traffic going to the remote port 80 and will block the traffic. You could work around this problem by using port 443 (HTTPS) and send your SSH traffic through stunnel. But, that is out of the scope of this article.

Remember that using this information to tunnel out of a network without permission is probably not ok. Always ask for permission before attempting to do this on someone else’s network.

network diagram

Preparation

How was this set up? Well, first of all the server has the ability to forward packets. You can configure this with (as root):

sysctl -w net.ipv4_forward=1

And uncomment the line in /etc/sysctl.conf to make it permanent.

Next thing to do is allow SSH tunnelling by setting PermitTunnel yes in /etc/ssh/sshd_config (and restart ssh after doing so).

You will also need to NAT the connections on the server:

iptables -t nat -A POSTROUTING -s 172.16.0.0/24 -o eth0 -j MASQUERADE

Save your iptables and load them in /etc/rc.local (before the return 0) to make this permanent.

bash -c "iptables-save > /etc/iptables.rules" iptables-restore < /etc/iptables.rules (in /etc/rc.local)

Connecting

Configuring the actual VPN is really easy. Just make sure you have an SSH key installed on the server so you can login password-less. Quick howto (on the client):

cd ~/.ssh && ssh-keygen -t dsa ssh-copy-id root@192.168.0.5 (while you are on the same network)

Put the following in the server’s /etc/network/interfaces:

iface tun0 inet static pre-up sleep 5 address 10.14.0.1 netmask 255.255.255.0 pointopoint 10.14.0.2

Put the following in the client’s /etc/network/interfaces:

iface tun0 inet static pre-up ssh -p80 -NTCf -w 0:0 66.66.66.66 pre-up sleep 5 address 172.16.0.2 pointopoint 172.16.0.1 netmask 255.255.255.0 up ip route add 192.168.0.0/24 via 172.16.0.2 up echo "search myhome.local\nnameserver 192.168.0.1" > /etc/resolv.conf up ssh 66.66.66.66 ifup tun0 down ip route del 192.168.0.0/24 down echo "nameserver 10.0.0.1\nsearch corporation.com" > /etc/resolv.conf post-down ssh 66.66.66.66 ifdown tun0

When you ifup tun0 on the client, it will activate tunneling, create both tun0 interfaces add routing to the remote network, change the local DNS resolver. When you ifdown tun0 on the client, it will remove the routing, restore the DNS resolver and stop tun0 on the remote machine.

To make it super easy, allow yourself (or a group with name vpn) password-less sudo rights to ifup and ifdown:

%vpn ALL=NOPASSWD: /sbin/ifup,/sbin/ifdown

You could then use these two aliases to connect/disconnect:

alias vpn_up="echo -n 'Staring ...'; sudo ifup tun0 > /dev/null 2>&1; echo" alias vpn_down="echo -n 'Stopping ...'; sudo ifdown tun0 > /dev/null 2>&1; echo"