Connect servers on a different network with Tinc VPN

Tinc VPN
Connecting servers can be handy for instance for monitoring, easy access, shared storage and so on. Especially when they are on different networks and you need them to play nice. There is a lot you can do with ssh but sometimes, you need more. We are going to connect 2 servers with a public IP over a Tinc VPN. This will allow both servers to access each other as if they were in the same network. The same principles could be used to secure a connection between servers that are in the same subnet for instance when you're running a VPS server. In that case, you would also need the interfaces to listen on the Tinc VPN IP instead of the local IP.

Server 1

First of all, install Tinc on the the server that all the other servers will connect to.:

apt-get install tinc

Create the necessary directories and files. <mynetworkname> is the name you want to give your VPN network. We chose a tun device buth other devices are possible such as a dummy device, raw_socket, tap and more. Read the official documentation to learn more.:

mkdir -p /etc/tinc/<mynetworkname>/hosts
vi /etc/tinc/<mynetworkname>/tinc.conf

...
Name = server1
AddressFamily = ipv4
Interface = tun0

Next we create the server host file. Per server there will be such a host file and the files will have to be interchanged between the servers in order for Tinc to work. The <public_ip> is the IP the other servers will use to connect to this server. We will use an ip in the subnet 10.0.0.0. Feel free to choose another range. Again, there are a lot more possibilities. Learn more

vi /etc/tinc/<mynetworkname>/hosts/<server>
...
Address = <public_ip>
Subnet = 10.0.0.250/32

Tinc works with public/private keypairs to secure the connection. We need to generate a public/private keypair for this host:

tincd -n <mynetworkname> -K4096

Generating 4096 bits keys:
............................................................++ p
.....................................++ q
Done.
Please enter a file to save private RSA key to [/etc/tinc/<mynetworkname>/rsa_key.priv]:
Please enter a file to save public RSA key to [/etc/tinc/<mynetworkname>/hosts/server1]:

The private key pair rsa_key.priv is created in /etc/tinc/<mynetworkname>. The public key is appended to the hosts config file /etc/tinc/<mynetworkname>/hosts/<server1>.


When the VPN is created, a tinc-up script is run. We need the tinc-up script to assign an IP to the VPN. A tun device is used for this. There are several scripts Tinc uses:

vi /etc/tinc/<mynetworkname>/tinc-up
...
#!/bin/bash
ifconfig $INTERFACE 10.0.0.250 netmask 255.255.255.0

There is also a tinc-down script for when the VPN connection is closed. The tun interface is taken down and deleted.:

vi /etc/tinc/<mynetworkname>/tinc-down
#!/bin/bash
ifconfig $INTERFACE down

The scripts need to be executable:

chmod 755 /etc/tinc/<mynetworkname>/tinc-*

After creating the Tinc configuration for the server the other servers will connect to, it's time to setup server 2. The setup is basically the same, but we do need to specify where this server needs to connect to.

Server 2

Again, install Tinc.:

apt-get install tinc

Create the hosts directory and tinc.conf. Here we also specify the server we want to connect to. In this example, server 1:

mkdir -p /etc/tinc/<mynetworkname>/hosts
vi /etc/tinc/<mynetworkname>/tinc.conf
...
Name = server2
AddressFamily = ipv4
Interface = tun0
ConnectTo = server1

Next we setup the host file in /etc/tinc/<mynetworkname>/hosts/<server2>:

vi /etc/tinc/<mynetworkname>/hosts/<server2>
Address = <public_ip>
Subnet = 10.0.0.251/32

Create the public/private keypair:

tincd -n <mynetworkname> -K4096

Generating 4096 bits keys:
.......++ p
.....................++ q
Done.
Please enter a file to save private RSA key to [/etc/tinc/<mynetworkname>/rsa_key.priv]:
Please enter a file to save public RSA key to [/etc/tinc/<mynetworkname>/hosts/server2]:

Create the tinc-up and tinc-down scripts:

vi /etc/tinc/<mynetworkname>/tinc-up
...
#!/bin/bash
ifconfig $INTERFACE 10.0.0.251 netmask 255.255.255.0

There is also a tinc-down script for when the VPN connection is closed.:

vi /etc/tinc/<mynetworkname>/tinc-down
...
#!/bin/bash
ifconfig $INTERFACE down

Make the scripts executable:

chmod 755 /etc/tinc/<mynetworkname>/tinc-*

Exchange keys

For the VPN connection to work, both servers will need the host file created on the other server. Only then a connection will be established. Copy the "server1" host file from server 1 to server 2. From server 2 copy the "server 2" host file to server 1.

You could use scp or even ssh to the respective server and copy the content of the host file. On both ends, you will need to end up with both host files:

/etc/tinc/<mynetworkname>/hosts
totaal 16
drwxr-xr-x 2 root root 4096 jan 27 14:23 .
drwxr-xr-x 3 root root 4096 jan 27 14:16 ..
-rw-r--r-- 1 root root  827 jan 27 14:13 server1
-rw-r--r-- 1 root root  823 jan 27 14:23 server2

Starting the VPN

To start the VPN, we will first try it in debugmode from server1. After the initial test, you can leave out both options.

  • -D means "don't fork and detach".
  • -d3 specifies the debug level.
tincd -n <mynetworkname> -D -d3

tincd 1.0.24 (Nov  8 2014 18:45:28) starting, debug level 3
/dev/net/tun is a Linux tun/tap device (tun mode)
Executing script tinc-up
Listening on 0.0.0.0 port 655
Ready

If you are not running tincd in debug mode, the command is:

tincd -n <mynetworkname>

More info can be found in the info page of Tinc (there is no man page):

Tinc will detach from the terminal and continue to run in the
background like a good daemon.  If there are any problems however you
can try to increase the debug level and look in the syslog to find out
what the problems are.

To stop Tinc, you might be surprised to find you can't use Ctrl-C. Use Ctrl \. On my keyboard (Belgian) this means some funcky key slamming. I need to press Ctrl, Alt Gr and \. Alt Gr is need to form the \ character.

On server 2, do the same. You should also see some output on server 1 as server 2 connects.:

tincd -n <mynetworkname> -D -d3

tincd 1.0.31 starting, debug level 3
/dev/net/tun is a Linux tun/tap device (tun mode)
Executing script tinc-up
Listening on 0.0.0.0 port 655
Ready
Trying to connect to server1 (public_ip port 655)
Connected to server1 (public_ip port 655)
Sending ID to server1 (public_ip port 655)
Got ID from server1 (public_ip port 655)
Sending METAKEY to server1 (public_ip port 655)
Got METAKEY from server1 (public_ip port 655)
Sending CHALLENGE to server1 (public_ip port 655)
Got CHALLENGE from server1 (public_ip port 655)
Sending CHAL_REPLY to server1 (public_ip port 655)
Got CHAL_REPLY from server1 (public_ip port 655)
Sending ACK to server1 (public_ip port 655)
Got ACK from server1 (public_ip port 655)
Connection with server1 (public_ip port 655) activated
...

If you have another active SSH session open to server 1, you can try to ping server 2. Do the same from server 2.

If all works, you still need to specify that you want the Tinc VPN network to start on boot time. To do this, you need to edit /etc/tinc/nets.boot or create it if it doesn't exist yet. Specify the VPN network you want to start at boot time.:

vi /etc/tinc/nets.boot
...
<mynetworkname>

Make sure your firewall / iptables allows traffic over port 655. Monitor /var/log/syslog and the debug output of the tinc command the connection fails.

More security

Tinc can also be run in a chroot and drop priviliges to a certain user after initialization. Additionaly, you can prevent Tinc from being swapped out. For convenience, the relevant parts of the Tinc info page:

'-R, --chroot'
     Change process root directory to the directory where the config
     file is located ('/etc/tinc/NETNAME/' as determined by -n/-net
     option or as given by -c/-config option), for added security.  The
     chroot is performed after all the initialization is done, after
     writing pid files and opening network sockets.

     Note that this option alone does not do any good without -U/-user,
     below.

     Note also that tinc can't run scripts anymore (such as tinc-down or
     host-up), unless it's setup to be runnable inside chroot
     environment.

'-U, --user=USER'
     Switch to the given USER after initialization, at the same time as
     chroot is performed (see -chroot above).  With this option tinc
     drops privileges, for added security.

'-L, --mlock'
     Lock tinc into main memory.  This will prevent sensitive data like
     shared private keys to be written to the system swap
     files/partitions.