Notes on programming

Hetzner DIY Private Networking with tinc

· 4 min read

Hetzner has a reputation for offering a sweet price/performance ratio, however, in a true Unix philosophy, it comes at a cost of having to do everything by yourself. Including Private Networking. Normally you only get one public IP and no private interfaces. I suspect they might have some clever routing rules in place for traffic to never leave the DC, but somehow I don’t really fancy sending unencrypted traffic over public IPs.

Luckily, I am a guy who has recompiled his kernel over a dozen of times because I’ve forgotten to enable a feature! Here I’m obviously referring to my hard-working persona and not my 640K memory, which btw, should be enough for everyone, haha!

tinc vs traditional VPN solutions

Usually, Virtual Private Network (VPN) solutions have a client-server architecture that gives you a star shaped topology, where everything has to go through a central node, but that’s not quite what I want. I want a peer-to-peer network where every node is connected to all the other nodes. Think LAN, only more resilient.

Network Topology

Full mesh routing via tunnelling and encryption is exactly what tinc does. Additionally, whenever possible, it will always send traffic directly to the destination, without going through any intermediate hops and because the VPN appears as a normal network device, there is no need to adapt any existing software! #mindblown

Private Networking and Outgoing Traffic costs

If you’re wondering whether this DIY Private Network will count against your outgoing traffic, then according to Hetzner the answer is NO (emphasis mine):

We only bill for outgoing traffic. Incoming and internal traffic is free. Internal traffic includes other Hetzner Cloud servers, other Hetzner Online dedicated root servers, and other Hetzner Online servers, services, or web hosting packages.

DIY Private Network vs DigitalOcean’s Private Networking

I had great fun with tcpdump, iptables and PKCS while working on this DIY private network. And by great fun, I of course mean me not reading the docs, misconfiguring things and then staring at the screen dumbfoundedly when things don’t work as expected. So, naturally, this would all be a big waste of time if I wouldn’t benchmark it against something! I picked DigitalOcean as they offer Private Networking as a simple tick box when creating a droplet. Ughhh, that cuts deep.

My objective is to run two tests - one where traffic goes over an encrypted tunnel and one without encryption. The outcome will be the average of 5 runs for each test.

Here’s my test setup:

Both DC locations are reasonably close to each other, so for me this will be as fair as it gets. Here’s my example playbook that I used for creating the mesh networks.

Hetzner

First test was no encryption run between two nodes. Allegedly, this still counts as internal traffic, so some black art has been applied. In any case, my test runs were clocking in at about 6.5 Gbits/sec:

$ iperf -c x.x.x.x
------------------------------------------------------------
Client connecting to x.x.x.x, TCP port 5001
TCP window size: 85.0 KByte (default)
------------------------------------------------------------
[  3] local x.x.x.x port 47526 connected with x.x.x.x port 5001
[ ID] Interval       Transfer     Bandwidth
[  3]  0.0-10.0 sec  7.12 GBytes  6.12 Gbits/sec

OMG, do you see it? 6.12 Gbits/sec!

Second test was over an encrypted tunnel between two nodes, averaging at about 390 Mbit/s:

$ iperf -c 10.10.1.x
------------------------------------------------------------
Client connecting to 10.10.1.x, TCP port 5001
TCP window size: 45.0 KByte (default)
------------------------------------------------------------
[  3] local 10.10.1.x port 43714 connected with 10.10.1.x port 5001
[ ID] Interval       Transfer     Bandwidth
[  3]  0.0-10.0 sec   460 MBytes   386 Mbits/sec

DigitalOcean

Same process - average of 5 runs for each test. One caveat tho - here I used the provided Private Network to run my tests.

Bandwidth was averaging at about 1.4 Gbits/s for unencrypted traffic:

$ iperf -c x.x.x.x
------------------------------------------------------------
Client connecting to x.x.x.x, TCP port 5001
TCP window size: 85.0 KByte (default)
------------------------------------------------------------
[  3] local x.x.x.x port 59560 connected with x.x.x.x port 5001
[ ID] Interval       Transfer     Bandwidth
[  3]  0.0-10.0 sec  1.57 GBytes  1.35 Gbits/sec

Things weren’t looking so great over an encrypted tunnel, only 200 Mbit/sec compared to Hetzner’s 390 Mbit/s:

$ iperf -c 10.10.1.x
------------------------------------------------------------
Client connecting to 10.10.1.x, TCP port 5001
TCP window size: 45.0 KByte (default)
------------------------------------------------------------
[  3] local 10.10.1.x port 46910 connected with 10.10.1.x port 5001
[ ID] Interval       Transfer     Bandwidth
[  3]  0.0-10.0 sec   237 MBytes   199 Mbits/sec

So, yeah. Hetzner kicks ass.