SSH tunneling is faster than OpenVPN, could it be?

Logically, VPN should be faster than SSH for tunneling, because:

  • It's running on UDP and not TCP (so no TCP over TCP)
  • It has compression

However, today I tested Redis replication over both methods.
I ran the test over an Ireland AWS VM, connecting to a US-East AWS VM.
Since my test case is Redis replication, this is exactly what I tested - I ran a blank Redis server, and after it finished loading, I executed slaveof the other server, and measured the time between Connecting to MASTER and MASTER <-> SLAVE sync: Finished with success. In between, I used

while 1; do redis-cli -p 7777 info | grep master_sync_left_bytes;sleep 1; done

To get a crude estimation of the speed.
SSH won by a long shot: ~11MB/s compared to OpenVPN's ~2MB/s.
Does that mean that all of what I reaserched was wrong, or have I grossly misconfigured my setup?

Update

I've made several test with the same dataset, and got these results:

  • OpenVPN
    • TCP:
      compression: 15m
      no compression: 21m
    • UDP:
      compression: 5m
      no compression: 6m
  • SSH
    defaults: 1m50s
    no compression: 1m30s
    compression: 2m30s

Update2

Here are the iperf results, with bidirectional tests (except SSH, where no return path is available)

| method           | result (Mb/s)|
|------------------+--------------|
| ssh              | 91.1 / N.A   |
| vpn blowfish udp | 43 / 11      |
| vpn blowfish tcp | 13 / 12      |
| vpn AES udp      | 36 / 4       |
| vpn AES tcp      | 12 / 5       |

Technical specs

I'm running CentOS 6.3 (server), CentOS 6.5 (client).
OpenVPN version is 2.3.2 (same as in Ubuntu 14.10, so no moldy version there)
My SSH tunnelling looks like:

ssh -f XXXX@XXXX -i XXXX -L 12345:127.0.0.1:12345 -N

My configuration file looks like:
server

port 1194
proto udp
dev tun0
topology subnet
log /var/log/openvpn.log

ca XXXX
cert XXXX
key XXXX
dh XXXX
crl-verify XXXX

cipher AES-256-CBC

server XXXX 255.255.255.0

ifconfig-pool-persist /etc/openvpn/ipp.txt
keepalive 10 120
comp-lzo
status /var/log/openvpn-status.log
verb 3
tun-mtu 1500
fragment 1300

persist-key
persist-tun

client

client

remote XXXX 1194

proto udp
dev tun
log /var/log/openvpn.log
comp-lzo

cipher AES-256-CBC
ns-cert-type server

# the full paths to your server keys and certs
ca XXXX
cert XXXX
key XXXX

tun-mtu 1500 # Device MTU
fragment 1300 # Internal fragmentation

persist-key
persist-tun
nobind

Thanks to kasperd's comment, I learnt that SSH doesn't suffer from TCP-over-TCP since it only moves packet data. I wrote a blog post about it, but the most interesting thing is the netstat output, proving that SSH indeed doesn't preserve Layer 3,4 data:

after tunneling, before connecting

backslasher@client$ netstat -nap | grep -P '(ssh|redis)'
...
tcp        0      0 127.0.0.1:20000             0.0.0.0:*                   LISTEN      20879/ssh
tcp        0      0 10.105.16.225:53142         <SERVER IP>:22              ESTABLISHED 20879/ssh
...

backslasher@server$ netstat -nap | grep -P '(ssh|redis)'
...
tcp        0      0 0.0.0.0:6379                0.0.0.0:*                   LISTEN      54328/redis-server
tcp        0      0 <SERVER IP>:22              <CLIENT IP>:53142           ESTABLISHED 53692/sshd
...

after tunneling and connecting

backslasher@client$ netstat -nap | grep -P '(ssh|redis)'
...
tcp        0      0 127.0.0.1:20000             0.0.0.0:*                   LISTEN      20879/ssh
tcp        0      0 127.0.0.1:20000             127.0.0.1:53142             ESTABLISHED 20879/ssh
tcp        0      0 127.0.0.1:53142             127.0.0.1:20000             ESTABLISHED 21692/redis-cli
...

backslasher@server$ netstat -nap | grep -P '(ssh|redis)'
...
tcp        0      0 0.0.0.0:6379                0.0.0.0:*                   LISTEN      54328/redis-server
tcp        0      0 127.0.0.1:6379              127.0.0.1:42680             ESTABLISHED 54328/redis-server
tcp        0      0 127.0.0.1:42680             127.0.0.1:6379              ESTABLISHED 54333/sshd
tcp        0      0 <SERVER IP>:22              <CLIENT IP>:53142           ESTABLISHED 52889/sshd
...

So I'm going to use SSH tunneling, since it seems that my OpenVPN isn't misconfigured or anything, just not the right tool for the job.


It depends what you are trying to achieve and what your priorities are. VPN connects you to a network and SSH to a machine. VPN is a bit more secure with the encapsulation, which SSH does not do.

Also, VPN allows all the traffic to easily go through it, versus SSH where you will have to force the applications.

Are you going to use AD at all? Because VPN will let you do that with much more ease.

I prefer SSH for speedy necessities and VPN for critical applications where I should spare the extra time.

Depending on the situation, I have used SSH in a VPN in case the VPN was compromised. This way someone probing would have to get through the SSH tunneling.