OpenVPN connection through SSH tunnel

Solution 1:

The simplistic approach to setting up your VPN connection through an SSH tunnel will not work. First problem: you are only tunneling the connection to the VPN server itself, which does not then allow all other traffic to be routed through the VPN server OVER the ssh connection (thus obfuscating the connection). The fix for this is to use a dynamic SOCKS[5] proxy and tell OpenVPN to connect via that proxy. Add to your OpenVPN config file:

socks-proxy localhost 6886
socks-proxy-retry

Then, start your ssh session with a dynamic SOCKS proxy:

ssh -D 6886 -N REMOTE

Then you can start your OpenVPN connection. However, this still has one more failing, at least assuming you want to redirect all traffic through the VPN (OpenVPN directive redirect-gateway def1). For that to work, you need to maintain a route to the SOCKS proxy end point that does not get masked by the routes added by the OpenVPN client. To do this, add another directive to your OpenVPN config that looks like this:

route REMOTE-IP 255.255.255.255 net_gateway default

You might be able to to use the hostname REMOTE in that directive, but you might need to resolve it to an IP address manually.

That should work, at least for ipv4 traffic. A quick google search turns up this blog post which does essentially the same thing, has good descriptions of what's going on, but seems to be more complicated in the solution (using a connection script)

Alternatively, you might also look at using obfs4proxy (e.g. this and this or packaged for ubuntu)

Solution 2:

I could successfully establish a connection to my Raspberry Pi (with PiVPN) over TCP and an external VPS. Then I did this:

allow the forwarding to public on your server (VPS/VPN). Change GatewayPorts to yes or add if it does not exists yet.

/etc/ssh/sshd_config:
GatewayPorts yes

Change proto udp to tcp (as ssh uses the tcp protocol)

/etc/openvpn/server.conf:
proto tcp

Again, change proto udp to tcp-client:

openvpn-client.ovpn:
proto tcp-client

Now start the ssh forwarding (0.0.0.0 to allow all IPv4 connections; -N to not start a bash on the server)

ssh -R 0.0.0.0:1194:localhost:1194 user@server -N

You should also check that your VPS/VPN-server allows the connection and has the right firewall settings. If you use ufw for iptables, simply do this:

ufw allow 1194/tcp
ufw enable

This may not be the fastest but it works for me.

Solution 3:

You don't need to run some other VPN through ssh. you can use ssh AS the VPN. see ssh's "-w X:Y" option.

This is a linux-centric answer. Presume a server, we'll call it "hub", to which ssh tunnel clients connect. They will use 172.17.2.0/24 as the VPN "carrier" network. Certain hosts are common and well known, we give them fixed configurations. Others can connect as well but must use other configurations.

#!/bin/sh -e
#
# make-ssh-tunnel HITHER YON INTERFACE GW
#
# HITHER ...... this host's VPN address.
# YON ......... $GW's VPN address.
# INTERFACE ... number of the tun device, same at both ends.
# GW .......... server host.
#
# /etc/ssh/sshd_config on $GW must include:
#   PermitRootLogin yes
#   PermitTunnel yes
# and clients must be able to ssh to $GW as root.
#
# this creates a star topology with $GW at center,
# which is generally the .1 address in the VPN /24 net.
# others connect and route through $GW to reach
# the other members of the /24 net.
# ________________________________________________
#
# the setup.
#
if [ "$#" = 0 ] ; then
    # automatic, for specific, known, regularly-connected hosts.
    case "`hostname -s`" in
    ThisHost) HITHER=172.17.2.2 IFACE=12 ;;
    ThatHost) HITHER=172.17.2.3 IFACE=13 ;;
    Another)  HITHER=172.17.2.4 IFACE=14 ;;
    *)        echo who are you? ; exit 1 ;;
    esac
    YON=172.17.2.1
    GW=hub
    SUBNET=172.17.2.0
else
    # manual, for random, probably temporary connections.
    HITHER="${1:-172.17.2.5}"
    YON="${2:-172.17.2.1}"
    IFACE="${3:-15}"
    GW="${4:-hub}"
    SUBNET="${YON%.[0-9]*}".0
    #
    [ "$HITHER" = "$YON" ] && echo "${0##*/}": identical addresses not allowed && exit 1
fi
#
# the business.
#
set -x
# 1st: do it there.
ssh -f -T -w $IFACE:$IFACE root@$GW \
"ifconfig tun$IFACE $YON pointopoint $HITHER netmask 255.255.255.255
 ifconfig tun$IFACE
 route -n | grep tun$IFACE"
# 2nd: do it here.
 ifconfig tun$IFACE $HITHER pointopoint $YON netmask 255.255.255.255
 ifconfig tun$IFACE
 route add -net $SUBNET/24 gw $YON
 route -n | grep tun$IFACE
#
# the afterthought.
#
# to make the tunnel a default route replacement:
#
# route add -host $GW gw 192.168.0.1 # that is, your real.defa.ult.route
# ip route add   0.0.0.0/1 via $YON
# ip route add 128.0.0.0/1 via $YON
#
# 1st preserves real route to $GW, avoiding route loop.
# 2nd and 3rd override default route without replacing it.
#
# in addition, $GW must NAT on behalf of the VPN hosts.
# iptables -t nat -A POSTROUTING -s 172.17.2.0/24 -o eth0 -j SNAT --to-source 11.22.33.44
# where --to-source is $GW's real external address.
#
# Embellish to taste.