SSH VPN with IP Masquerading (NAT)

I’ve written before about how to access SNMP agents (or other TCP or UDP services) in a network when you only have SSH access. Running a SSH VPN and then running IP Masquerading (NAT) in the remote end is the solution for me so far. Here is how it is done.


In the figure above, the Remote Server could be any TCP or UDP service in the remote network. My personal itch was to access SNMP agents in a remote network.

About and You’ll need to choose a network that isn’t being used in either side of the link. I’ve chosen the network here but you can choose whatever makes sense to you. Just make sure it isn’t already used on either side.

First, we’ll set up the SSH VPN, and then we’ll add the networking trimmings (NAT and routes) so we can access the entire remote network from the SSH client. Finally I’ll also briefly cover PPP over SSH (a similar solution) which could be handy in some situations. Regardless, you’ll need root access on both SSH client and SSH server machines. And of course you’ll need SSH access to the SSH server! :-)


Following a good resource, it is really rather simple.

First on the server, make sure that /etc/ssh/sshd_config contains the PermitTunnel yes setting, or you’ll get an error like: channel 0: open failed in the following.

Now, from the SSH client:

sudo SSH_AUTH_SOCK=$SSH_AUTH_SOCK ssh -w 0:0 root@server

That establishes the tun0 devices in both ends. Now we need to configure them. On the server:

ip link set tun0 up
ip addr add peer dev tun0

On the client:

ip link set tun0 up
ip addr add peer dev tun0

ifconfig on both client and server should show that you’re up and running. Test it like this from the client:

$ ping
PING ( 56(84) bytes of data.
64 bytes from icmp_req=1 ttl=64 time=13.1 ms
64 bytes from icmp_req=2 ttl=64 time=13.7 ms

Now the SSH VPN is up and running. What this means is you’ll be able to access any resource on the SSH server, but not yet everything in the network.

Please, for more details and hints about this (especially about the different approaches to root and SSH) see the good resource.

IP Masquerade (NAT) and routes

The goal is that we want to access any equipment in the remote network without having to make any changes in the remote network. That is done with IP Masquerading on the server side and appropriate routes on the client side (see diagram above).

To set up, do this on the server side (assuming the remote network is accessed with eth0):

echo "1" > /proc/sys/net/ipv4/ip_forward
iptables -t nat -A POSTROUTING -o eth0 -j MASQUERADE

Now, on the client side:

route add -net tun0

That should be it! You can access all of the remote network from the SSH client as if you were locally connected. Repeat this route command for all routes in the remote network you need access to.


If the remote network has its own DNS server, add its IP address to /etc/resolv.conf and you’ll be able to access them by name too.

SSH VPN alternative: PPP link over SSH

If for some reason the SSH VPN doesn’t work for you (e.g. old SSH version or you can’t enable the PermitTunnel yes setting), then you might want to use PPP over SSH instead. This requires the ppp package.

sudo /usr/sbin/pppd noauth pty \
“SSH_AUTH_SOCK=$SSH_AUTH_SOCK ssh -t -e none root@server /usr/sbin/pppd passive noauth”

The tricky part here is that you can’t enter a sudo password on the remote side. ( I don’t think so anyway ). So you’ll need to be able to either log in directly as root (which is fine if you’re using SSH keys), or have sudo set up to not require a password for pppd. I chose the former.

Now you’ll have a ppp0 interface on both sides already configured with IP addresses and everything. Just continue to the “IP Masquerade (NAT) and routes” part (use ppp0 instead of tun0 though)

More information

Keep in mind, that if all you have is SSH (which runs over TCP), performance is going to be problematic. See Why TCP Over TCP Is A Bad Idea. That is part and parcel with the SSH-only access and therefore unavoidable regardless of solution.

I found all my information in man pages and here:

Last, I wish sshuttle would do the trick, but for UDP it doesn’t quite do the job yet and requires a newer kernel.

2 thoughts on “SSH VPN with IP Masquerading (NAT)”

  1. Hello,
    Thanks for your article.

    I am currently facing a problem when I do the command:
    ip link set tun0 up
    root@ubuntu:/etc/network# ip link set tun0 up
    Cannot find device “tun0″
    root@ubuntu:/etc/network# sudo ip link set tun0 up
    Cannot find device “tun0″

    Can you please guide me..

Leave a Reply

Your email address will not be published. Required fields are marked *

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <s> <strike> <strong>