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
  • 2
    SSH supports compression as well, so that isn't necessarily something different between OpenVPN and SSH. Have you tried disabling compression on both side? When you perform the transfer over OpenVPN, run top or something on your client/server. Are there any obvious signs that you are maxing your CPU/Memory/etc with the VPN connection? – Zoredache Dec 17 '14 at 17:41
  • 2
    It seems unlikely for a AWS hosted system, but there is a small possibility that UDP is getting rate limited or something. Have you tried doing OpenVPN over TCP? – Zoredache Dec 17 '14 at 17:41
  • 3
    @Nitz TCP tunnels in ssh do not use any TCP over TCP. In fact the ssh client is usually run with insufficient privileges to even do it. And no, ssh does not strip any TCP headers from packets, because it never even touches a TCP packet. ssh is just an application making use of the TCP stack in the kernel, like any other application. Data travels through one TCP connection from some program to the ssh client. The ssh client encrypts the data and send it through the TCP connection to the server. The server decrypts it ans send it through the third TCP connection to a program at the other end. – kasperd Dec 18 '14 at 10:37
  • 2
    Sure there might be a little more overhead with OpenVPN because it has the extra IP/TCp headers. But that shouldn't make a difference of 4-10 times slower. If the difference was in the 5-10% slower range I might be tempted to blame that. The reason you might want to still investigate is that this could be a symptom of some underlying problem that might be impacting other things in a way that is less obvious. – Zoredache Dec 18 '14 at 20:35
  • 2
    @Nitz If I understand you correctly, you are saying that the unencrypted packets entering the virtual interface are 1424 bytes, but the encrypted packets send on the physical interface are only 160 bytes. That would indicate a pretty extreme fragmentation happening at the VPN layer or the UDP/IP layer beneath it. That could certainly explain the performance problem. The packets on the virtual interface should be something on the order of 1300-1400 bytes. The packets on the physical interface should be something on the order of 1400-1500 bytes. – kasperd Dec 20 '14 at 23:13

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.

  • 2
    I'm running redis over the tunnel, so a single port suffices to me. I was just amazed by the fact that VPN is not always the best solution for tunneling network traffic – Nitz Sep 17 '15 at 6:10

Your Answer

 

By clicking "Post Your Answer", you acknowledge that you have read our updated terms of service, privacy policy and cookie policy, and that your continued use of the website is subject to these policies.

Not the answer you're looking for? Browse other questions tagged or ask your own question.