Tunneling OpenVPN Through SSH

I have recently discovered that it is fairly easy to tunnel OpenVPN through SSH. This is useful if you are behind a restrictive firewall that uses SPI to block services rather than plain old port blocking. An SPI firewall is able to distinguish between one packet type and another, without just checking the port that is in use. You can, of course, get a much more in-depth and accurate account of what SPI does/doesn’t do from Wikipedia, however that it’s really the purpose of this post.

You’ll need root access to the OpenVPN Server, as you have to change some of the server config files

So, on to the technical part of the procedure. You need to do the folllowing:

  1. Set the OpenVPN server config file to use TCP rather than UDP. This is done by changing the line proto udp to proto tcp in the server config file (normally located at /etc/openvpn/server.conf).
  2. Set the OpenVPN client config file to use TCP rather than UDP. You can do this by changing the line proto udp to proto tcp-client in the client config file.
  3. Change the OpenVPN client config to connect to localhost rather than the remote server address. This is done by changing the “remote” line of the server to remote localhost 1194
  4. Create an SSH tunnel between the client machine and the OpenVPN Server, and forward from remote:1194 to localhost:1194. This can be done by running the command:
    ssh user@server -L 1194:localhost:1194 on the client machine (assuming you’re running Linux/Unix with the OpenSSH client binary installed)

All being well, after making those config file changes and creating your SSH tunnel, you’ll be able to tunnel OpenVPN through SSH.

It’s not the ideal solution – the is a lot more overhead when running OpenVPN in TCP mode, and even more when tunneling TCP over TCP, which is what you’re doing by using an SSH tunnel with VPN Traffic. However, needs must – and this is one way of getting round an SPI Firewall when SSH connections are allowed

7 thoughts on “Tunneling OpenVPN Through SSH

  1. Didn’t you encounter any problems with routes when using this setup? The OpenVPN will set up the default route through tun/tap interface and a secound route to remote through the previous gateway. If the remote is set up as localhost, you will not get a route to where the OpenVPN server really is. This makes the SSH connection (and the tunnel) fail after a while, as it tries to route its packets through the tun/tap interface.

    1. I was concerned that this would be the case – but I had to use this set up for some time, and didn’t run into any trouble. My assumption was that because the SSH connection was established before OpenVPN set the new route up, the original route carried on being used – but I’m not sure!

  2. I ran into the exact problem that Andrzej described: the ssh tunnel drops after a few seconds
    due to trying to route through the OpenVPN connection.

    The solution is to set up a direct route to your server, using the current default route host, before starting the ssh tunnel:

    route add server current-default-route-host

    where “server” is the IP address of the OpenVPN server and “current-default-route-host” is the IP address of the current gateway to the Internet (the gateway for destination “” or “default” as given by route -n
    or netstat -rn).

    This seems to work: I am posting this comment through just such a tunnel!

      1. He forgot a couple a couple small things. It should be:

        route add -host gw

        I have an ISP that is doing DPI on OpenVPN traffic, so this has been working great for me. If you want to initiate the tunnel on startup you can add a few lines to your /etc/network/interfaces config file (in Debian, at least). This will make it so the tunnel is brought up right after your network interface(s), and before OpenVPN (if you are running it as a daemon).

        # Adds the route to the VPN server, as described above

        post-up route add -host gw

        # Starts the SSH tunnel (assumes you are not initiating the tunnel as root)

        post-up su username -c “ssh -f -N -4 -p XXXX -D localhost:XXXX username@”

        # Removes the route when the network interface(s) are brought down

        pre-down route del -host gw

        You could add a line to kill the tunnel when the network interface(s) are brought down as well, I just could not think of an elegant approach to it, and figured it was not a big deal anyway since the tunnel will get disconnected on shutdown or reboot. I guess if you regularly brought interfaces up/down it would be helpful.

        This will only work if you are using key authentication, otherwise SSH will be waiting for a password and network initialization will just get stuck. Restart networking from a local console if possible before rebooting to make sure it works; if it gets stuck trying to initialize your network interfaces on boot you’ll have to go into single user mode to modify the network config file, which is a bit of a pain.

        Alternatively, just use something like AutoSSH 🙂 It is a better option anyway since it will ensure that the SSH tunnel stays connected, and it can be run as a daemon. I will probably be switching to it soon.

Leave a Reply

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