Not to be confused with a VPN service Linux VPN’s are a great way to allow a geographically diverse collections of computers to communicate as if they were all on the same Local Area Network (LAN).
- Companies with people working from home who need to as as-if they were in the office
- Companies with multiple offices who need to work as one
- Families with one or two members looking after everyone else’s computer
- Home workers or hobbyists wanting to access their hosted services as if they were in the house
OpenVPN is probably the most well-known options and has a number of Pro’s, for example it runs across a number of Operating Systems rather than just Linux. But then given it’s all about security, one might ask what’s the point if you’re going to install it on certain other Operating Systems. I can think of many Con’s however, the fundamental issue being that it implements a point-to-point (or star) protocol.
(caveat; I’ve not used OpenVPN for some time, so if any of this has changed, please update me!)
tinc implements a mesh protocol, which means you’re not just connected to one server. There is no effective difference between clients and servers, you become a node and are able to connect to any other node. (which is rather better than point-to-point in terms of resilience) Again in terms of resilience, fail-over / reconnects tend to be transparent. People familiar with OpenVPN will be aware that if your OpenVPN connection drops for any reason, by the time it’s reconnected your SSH sessions may well have expired or decided to drop. With tinc this typically doesn’t happen unless you suffer a prelonged outage or try to put lots of data over your paused ssh session.
So for example if you’re running a remote system upgrade over a VPN and you’ve forgotten to start it with screen, OpenVPN is a bit of a worry.
Whereas this can be scripted, I’m doing this in detail from first principles to hopefully demonstrate how it all fits together. This example is using Ubuntu, it will be the same or similar on other distros.
We’re going to create a VPN between two local machines called star and moon, so starting on machine star; (I’m working as root, if you want to do this as a user, insert sudo’s as required);
apt install tinc
This will create a skeleton setup in /etc/tinc. Now by default tinc supports, nay expects you to want to run multiple vpn’s, so inside this folder you will want to create a sub-folder for your VPN, which we’re going to call space. Inside this sub-folder we’re then going to want to create a private and public key;
mkdir space cd space tincd -K 2048 -c `pwd`
When running tincd with -K it will automatically generate the keys for you. 2048 is the size of key to use (you can pick your size so long as it’s at least 512). Then you need to tell it where to put the keys, the long hand is /etc/tinc/space, however pwd will generate the current working directory, and back-ticks will evaluate the command in-line.
Next you need a couple of scripts to manage your VPN interface, these are literally templates that I guess tincd could create for you, but …
#!/bin/sh ifconfig $INTERFACE down
#!/bin/sh ifconfig $INTERFACE 192.168.240.1 netmask 255.255.255.0
Note here that we’ve chosen an address range to run our VPN on. If you don’t know much about addresses, all you really need to know is whether you have another network on that address range, and if the answer is that you don’t know, this one is probably Ok.
Note about address ranges;
Anything on 192.168.x.x is a range that is not carried on the Internet, hence is safe to use for your local network. The caveat here is that your local router will probably be using something in this range for your local network and you need to avoid overlapping it. For a BT hub / router the default is typically 192.168.1.0/24, so usually 192.168.2 and up is safe.
Once you’ve created your scripts, make sure the computer can execute them;
chmod +x tinc-down tinc-up
The remaining file we need to look at is the main tinc configuration file, tinc.conf, into which we will need to put;
Name=star Port=8620 PingInterval = 3 PingTimeout = 2 ConnectTo=moon
And we’re done with the basic configuration. Next we need to tell tinc about the hosts it should expect to hear from, so we’ll need to create a hosts folder, and into it we can start by adding a file to describe this host.
mkdir hosts cd hosts vi star
We have another choice to make at this point, each different tinc VPN runs on it’s own port, and even if you only have one VPN, you still need to allocate a port for it. In this instance we’re going to use 8620. We’re also going to need to know the addresses of the two machines.
In this example both machines are directly addressable via the local area network. The same example can be used if only one machine is directly addressable, for example if one machine is hosted on the Internet. If neither machine is directly addressable (say both machines are behind NAT routers), the example needs a slight modification, but is still relatively easy.
Address=192.168.1.123 Subnet=192.168.240.1 Port=8620 -----BEGIN RSA PUBLIC KEY----- MIIBCgKCAQEArLeDNz9V/tllDDopJXzuB119Jnpui67sKpHIIhbXn52atXPJnMc7 fz2CsK3ecns377hZyNGfaBFXVihQeQ19GmUQvmp1DdEx3RchtHSg4b9xFL/FywGd Xw3Snd+R1YfNSl7mxgNLno/CoT6XPgcEDuG4I56G6hfz0sqEFV80IEXimeGRLPQl cEU5QRR+VMbY1Fxp759IS3C60zf40NtBLhuvAJ6isOBOH8vZDJG9cN1TWjzOcSPn L3QMTZ8+t3/jbnUxJtbZ3yapxYEEyEAQCzuVJR9gBV1P2xQUqVvL4/1sOzzEstOp bafWo9aa/GHe5dpWdR7XNDWmIdHFbdzIvwIDAQAB -----END RSA PUBLIC KEY-----
So your version of this file will contain the real address of your star, the Subnet will match the address you chose in tinc-up, and the port will be your chosen port. The key section will be the contents of your /etc/tinc/space/rsa_key.pub which was auto-generated by tincd -K.
So we’re now pretty much done with star and you need to repeat this process with moon. Things that will be different;
- tinc-up will contain a different address (i.e. the address you wish to use to refer to moon)
- tinc.conf the name will be moon and the ConnectTo will be star
- hosts/moon the address will be the actual IP address of moon, the Subnet will be the address from moon’s tinc-up, and the key will be moon’s rsa_key.pub.
So moon will be identical to star, except for the few configuration items that are particular to that individual host. There is one remaining task, which is to copy the contents of hosts between machines. i.e. star needs the hosts entry for moon, and moon needs the hosts entry for star.
Your folder should now contain files something like this;
$ find . -ls drwxr-xr-x 3 root root 4096 Sep 5 12:17 . -rwxr-xr-x 1 root root 35 Sep 5 12:16 ./tinc-down drwxr-xr-x 2 root root 4096 Sep 5 12:18 ./hosts -rw-r--r-- 1 root root 480 Sep 5 12:18 ./hosts/moon -rw-r--r-- 1 root root 481 Sep 5 12:18 ./hosts/star -rwxr-xr-x 1 root root 66 Sep 5 12:17 ./tinc-up -rw-r--r-- 1 root root 68 Sep 5 12:17 ./tinc.conf -rw------- 1 root root 427 Sep 5 12:16 ./rsa_key.pub -rw------- 1 root root 1676 Sep 5 12:16 ./rsa_key.priv
And assuming you have no firewalls in place to stop communication between the two machines you should now be able to start the VPN on each machine and communicate. So on each machine;
service tinc@space start
Now add a couple of handy references to the VPN addresses you’ve chosen into your /etc/hosts file;
192.168.240.1 star 192.168.240.2 moon
And from any machine you should be able to ping yourself and the other node;
$ ping -c1 star PING star (192.168.240.1) 56(84) bytes of data. 64 bytes from star (192.168.240.1): icmp_seq=1 ttl=64 time=0.052 ms --- star ping statistics --- 1 packets transmitted, 1 received, 0% packet loss, time 0ms rtt min/avg/max/mdev = 0.052/0.052/0.052/0.000 ms $ ping -c1 moon PING moon (192.168.240.2) 56(84) bytes of data. 64 bytes from moon (192.168.240.2): icmp_seq=1 ttl=64 time=0.742 ms --- moon ping statistics --- 1 packets transmitted, 1 received, 0% packet loss, time 0ms rtt min/avg/max/mdev = 0.742/0.742/0.742/0.000 ms
And this is the beauty of a mesh network, you’ve now seen all the configuration there is. For another node, repeat the above instructions. All you need is to pick a new IP address from the 192.168.240 range (say 3), and when you have a new file for your new node in hosts, copy it to the other nodes, so they know about it. Then amend ConnectTo on the nodes you would like to make an initial connection to your new node.
Note on ConnectTo
The mesh network implements a degree of auto-discovery however it effectively needs to be pre-seeded using ConnectTo. So if star connects to moon, then moon connects to new_node, when the connection is up, star will work out that new_node is there and whether it can make a direct connection. The key here is that if the initial connection betweem star and moon fails, it won’t know about new_node, so it’s best to have a couple of ConnectTo’s per node so a single node failure doesn’t stop the pre-seeding process.
Now, I didn’t say the configuration was completely painless (!) however it is relatively straightforward when you have a recipe to follow. The only thing I would add would be to start the VPN when each node starts up, you will need to add;
systemctl enable tinc@space
To each node. If the @ in the service command and systemctl command is new to you, it’s used to manage multiple instances of the same service. So the format is service @ instance.
If anyone tries this out, do let me know, especially any bits I can improve on. Just a general plug, tinc is a low-memory high performance secure VPN. Like anything it can be mis-configured or abused, but thus far over the last (10?) years, it’s not given me any cause for concern.