Setting up a OpenVPN server on Linux

openvpn-logoI sometimes want to access my home network when working remotely in order to access my private files or machines in my network. Opening up the Samba ports for example in your router to the bad world outside is the most stupid thing to do, so in order to gain access we need to setup a VPN connection. There are several ways to accomplish this and in this example I will be installing the versatile OpenVPN software which can act as a server and client and is opensource (and therefore available on almost any platform).

In this post we will set up the OpenVPN server (service), create the needed keys for the VPN authorization, set up the VPN tunnel interface and create a sample client config to connect with. The instructions are run as root.

Installing the software:
For the server-side we only need to install 2 packages and after installation copy the easy-rsa key generation tools:

For Debian / Ubuntu:
apt-get install openvpn easy-rsa

For Arch Linux:
pacman -Sy openvpn easy-rsa

Setting up the CA:
Copy the easy-rsa key generation tools:
mkdir /etc/openvpn/easy-rsa/
cp -r /usr/share/easy-rsa/* /etc/openvpn/easy-rsa/

Now open the following file to change the variables used for key generation later on:
nano /etc/openvpn/easy-rsa/vars

Scroll a bit down until you reach the following block and change it to your situation and save your changes:
export KEY_COUNTRY=""
export KEY_PROVINCE=""
export KEY_CITY=""
export KEY_ORG=""
export KEY_EMAIL=""
export KEY_OU=""

Now we will generate the actual CA using the following commands:
cd /etc/openvpn/easy-rsa/
mkdir keys
source ./vars
./clean-all
./build-ca

It will ask several questions and the answers should already be filled with the content you changed earlier so we can just enter through the questions to accept them. Should you have made a typo you can change it in the appropriate question.

Create the server certificate and key:
Now that the CA bundle is generated we need to create a certificate and key for the server itself as well:
./build-key-server `hostname`

This will generate a certificate and key based on the hostname of the server at that time which should be sufficient for most setups, should you not want this you can change `hostname` for the hostname you want. It will ask you if you want a password on the certificate which I answered no to as I will sign the client certificates later on. The last 2 questions should be answered yes to (for signing and committing the certificate).

Now we want to generate the Diffie-Hellmann keys as a last step in creating the server certificate:
./build-dh

It says it will take a long time, on my Celeron system it took a couple of seconds… 🙂

Copy the generated certificate and key into the /etc/openvpn folder:
cd keys
cp `hostname`.crt `hostname`.key ca.crt dh2048.pem /etc/openvpn/

Create the client certificate and key:
Now that the CA and the server cert/key are generated and moved into place we need to start creating certificates for the clients that will need access to the VPN. The steps are almost the same as for the server:
cd /etc/openvpn/easy-rsa/
./build-key CLIENT_NAME

The questions asked are the same as when generating the server certificate but for better security you should set a password on the client certificate and key. Should the certificate get leaked on the internet they are useless as the password is still needed. Would you have a certificate without password they would immediately have access unless the certificate is revoked on the server. At the end you need to sign and commit the certificate by answering “y” 2 times.

Now we want the needed client-side files together. Therefore create a folder, in my case I’ve used /root/CLIENT_NAME/ (substitute CLIENT_NAME for the actual client name):
mkdir /root/CLIENT_NAME
cd /root/CLIENT_NAME
cp /etc/openvpn/ca.crt ./
cp /etc/openvpn/easy-rsa/keys/CLIENT_NAME.crt ./
cp /etc/openvpn/easy-rsa/keys/CLIENT_NAME.key ./

Now that we have the files for the client together we want to zip it for easy distribution:
zip CLIENT_NAME.zip ca.crt CLIENT_NAME.crt CLIENT_NAME.key

You can email this zip or put it on removable media for easier distribution!

We are generating the client certificate on the server itself, that itself is no big deal but you need to keep in mind that if someone ever gains unwanted access to your server they are able to steal the certificates/keys generated. For best security you should remove the certificate and matching key once these have been distributed to the client itself!

Adding extra clients:
That is simple, just follow the steps metioned above!

Setting up the OpenVPN server:
Now that all certificates are generated we can start configuring the OpenVPN server, we start by creating a new configuration file:
nano /etc/openvpn/server.conf

The options may vary based on what you want to achieve with the VPN, my setup is done as follows:
# Global configuration
port 1194
proto udp
dev tun
topology subnet
# Certificate location
ca ca.crt
cert SERVER_HOSTNAME.crt
key SERVER_HOSTNAME.key # This file should be kept secret
dh dh2048.pem
# Network configuration
server 10.8.0.0 255.255.255.0
push "route 192.168.0.0 255.255.255.0"
ifconfig-pool-persist ipp.txt
keepalive 10 120
comp-lzo
persist-key
persist-tun
# Logging
status openvpn-status.log
verb 3

A little explanation on the config: we use UDP port 1194 for the OpenVPN service and will use a TUN device (virtual) for the system. The certificate section is self-explanatory, here SERVER_NAME needs to be changed with the actual name used. For the network part we bind the TUN device to the 10.8.0.0/24 range. The route that’s being pushed is optional should you want access to the internal network of the server as well which is what we want mostly, since my network is build up on the 192.168.0.0/24 range I push it as shown. We also use LZO compression on the VPN sessions initiated, there is a sidenote though because it will be more resource consuming for the CPU to compress/decompress the data. If you use a embedded device for the VPN server you want to disable this, for any “modern” hardware this can be left on.

Now that the configuration is performed we want to start the OpenVPN service:

For Debian / Ubuntu:
service openvpn start

For Arch Linux:
systemctl enable openvpn@server.service
systemctl start openvpn@server.service

Note the @server for the Arch Linux method. The name you put there is a direct link to the OpenVPN config, so here we named it “server.conf” which makes openvpn@server. Have you changed the name of this config you should also change it in the openvpn@ part!

Now that the OpenVPN server has started we can check if it’s running, you can check this by listing the interfaces on the system, a ifconfig on my Arch Linux server will show the tun device:

tun0: flags=4305 mtu 1500
inet 10.8.0.1 netmask 255.255.255.0 destination 10.8.0.1
unspec 00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00 txqueuelen 100 (UNSPEC)
RX packets 0 bytes 0 (0.0 B)
RX errors 0 dropped 0 overruns 0 frame 0
TX packets 0 bytes 0 (0.0 B)
TX errors 0 dropped 0 overruns 0 carrier 0 collisions 0

Reaching the network behind the OpenVPN server:
With the setup above you will be able to reach the VPN server and work on that machine. If you want to be able to access the machines on the same network as the VPN server we need to make some additional changes.

We need to enable ipv4 forwarding first in systctl:
sysctl -w net.ipv4.ip_forward=1

If you want to make this change permanent after a reboot you need to add this option to:
/etc/sysctl.conf

We also need a couple of iptables entries, the following will do:
iptables -I FORWARD -i tun0 -o enp5s0 -s 10.8.0.0/24 -d 192.168.0.0/24 -m conntrack --ctstate NEW -j ACCEPT
iptables -I FORWARD -i tun0 -o enp5s0 -s 10.8.0.0/24 -m conntrack --ctstate NEW -j ACCEPT
iptables -I FORWARD -m conntrack --ctstate RELATED,ESTABLISHED -j ACCEPT
iptables -t nat -I POSTROUTING -o enp5s0 -s 10.8.0.0/24 -j MASQUERADE
iptables -t nat -I POSTROUTING -o enp5s0 -s 192.168.0.0/24 -j MASQUERADE

You need to change the interface names matching the ones on your server. In this example enp5s0 is my network interface, the tun0 normally don’t need to change.

You need to save these rules to a file, say:
/root/iptables-vpn.ipt

Make it executable:
chmod +x iptables-vpn.ipt

Now you can insert the iptables entries after a reboot by logging in as root and issuing:
./iptables-vpn.ipt

In addition you may need to open up port 1194 in your router/gateway/modem in order to gain access from outside your home network to the VPN server, refer to the manual of your model on how to achieve this.

That’s it! You’ve now set up a OpenVPN server! Distribute the client certificate and keyfile with the CA certificate to the client that needs to connect to the VPN server and configure the clientside based on certificate authentication.

Setting up the client:
I won’t go extremely in-depth here because there are many ways to do this. I wanted to access the VPN from my laptop, so I needed a GUI program in my desktop environment which could assist me. The Network Manager packages can aid in this, so we need to install it:

For Debian / Ubuntu:
sudo apt-get install network-manager-openvpn-gnome

For Arch Linux:
sudo pacman -Sy networkmanager-openvpn

You may need to log out and log in again in order to see the new option for setting up a OpenVPN connection. Now you can add a new OpenVPN connection:

VPN tab: Enter the server URL/IP in the gateway field, the connection type needs to be “Certificates (TLS)” and enter a name for the VPN connection. Select the certificates in the matching fields. Select the advanced button and on the new window check the “LZO compression”.
IPv4 tab: Select the “Routes…” button and select “Use only for resources on this connection”. If you don’t check this, all connections will flow through the VPN instead of the network you are trying to reach.
IPv6 tab: The same as for IPv4 tab and should only be set if you use IPv6.

Revoking a client certificate:
An essential part of maintaining a VPN server is to be able to revoke a client certificate (for example if a client is compromised) and denying access to the VPN. For this we need to set up a CRL (Certificate Revoking List) and configure OpenVPN to check that list first if a client connects.

First we need to create the CRL:
cd /etc/openvpn/easy-rsa/
source ./vars
./revoke-full CLIENT_NAME

Change CLIENT_NAME to the actual client name you wish to revoke.

Once the client certificate has been revoked, a file “index.txt” will be created in the keys folder:
keys/index.txt
Which will contain the revoked client information.

You may wish to examine the CRL file a bit further:
openssl crl -in keys/crl.pem -text

We also need to change the OpenVPN server config to actually check the CRL file if a client connects, open up the config:
nano /etc/openvpn/server.conf

Add the following line in the config:
crl-verify keys/crl.pem

And restart OpenVPN to make the change active:

For Debian / Ubuntu:
service openvpn restart

For Arch Linux:
systemctl restart openvpn@server.service

If now a client connects with a revoked certificate you will see a log entry in the syslog with this information!

5 Comments

  1. Please DO NOT EVER store easy-rsa files on a publicly available server. Those files should ideally be stored on an offline media, only to be made available when you want to create new or revoke certificates.

    If you loose control over the CA key, you can no longer trust any certificate issued by that CA. In such a case an attacker can issue new certificates for both clients and servers without your knowledge.

    The server requires 4 files in addition to the config file: server key, server certificate, CA certificate and the DH params file. The client needs 3 files in addition to the config: client key, client certificate and CA certificate. The rest of the files inside the easy-rsa directory should be strictly off-limit.

    Further, avoid creating keys and DH parameters on equipment with poor random entropy. If the randomness is predicted by an attacker, breaking your keys and VPN configuration gets far easier. Ideally, do this on bare-metal equipment with proper randomness or at least have a good entropy gathering daemon configured and running.

  2. Nice write up, even a windows guy like me was able to follow it.

    • Then it must be good! 🙂

      Just kidding, nice to read you were able to follow it!

  3. Thanks for the posting,. It’s nice article and cover all open-vpn setup and configuration 🙂

    • Thank you for your compliment :)!

Leave a Reply

Your email address will not be published. Required fields are marked *