Set up a Hardened OpenVPN Server on Debian 9

OpenVPN is a tool for creating network tunnels between groups of computers that are not on the same local network. This is useful to remotely access services on a network or computer without making those services publicly accessible. When integrated with OpenSSL, OpenVPN encrypts all VPN traffic providing a secure connection between machines.

An OpenVPN connection consists of two flow channels between the server and clients: the Control Channel and the Data Channel. A client connects to the server by initiating a TLS session over the control channel, in which credentials are exchanged between server and clients to establish the data channel. The data channel is the encrypted pipeline in which all traffic between server and clients is then transmitted.

This guide is the first of a three-part series. Part one sets up a VPN server on Debian and prepares the access credentials for client devices. This VPN can be used to host internal services such as websites, game servers or file servers.

Part two shows you how to set up a routed VPN so all traffic from client devices is tunneled through your Linode to the internet. Part three takes you through setting up the client-side software for various operating systems, including mobile platforms.

Before You Begin

Familiarize yourself with our Getting Started guide and set your Linode’s timezone.

This guide will use sudo wherever possible. Complete the sections of our Securing Your Server guide to create a standard user account, harden SSH access and remove unnecessary network services. Do not complete the steps in the Creating a Firewall section. This guide has instructions specifically for firewall rules for an OpenVPN server.

Update the system:

sudo apt update && sudo apt upgrade

Managing the OpenVPN Environment

The first method uses OpenVPN Community Edition, where server and client configurations are manually edited and client credentials are distributed to their respective devices using SCP or SFTP. Alternatively, you could copy credentials to a desktop computer, edit them and then transfer them by USB.

The second method uses OpenVPN Access Server, a server-side application which lets you configure OpenVPN with your web browser. Client machines access a private URL from which to download their credential packages.

For small applications, OpenVPN Access Server is the more streamlined and user-friendly solution. The free version allows up to two simultaneous users. Although each user can have as many client devices as they like, a user’s clients will all have the same keys and certificates; more can be added by buying licensing. For more advanced configurations than what the GUI offers, you would still need to edit the VPN’s configuration files.

Networking Configuration

OpenVPN currently does not support a dual-stack configuration from a single instance where clients can connect to a server simultaneously using IPv4 and IPv6; one transport layer must be chosen or the other. Furthermore, only OpenVPN versions 2.3 and above support IPv6 over TUN devices. With versions earlier than 2.3, IPv6 can only be used with TAP devices.

This series assumes your VPN will operate over IPv4 only. If you instead wish to use IPv6, see OpenVPN’s documentation for more information.

IPv4 Firewall Rules

Switch to the root user.

su - root

Flush any pre-existing rules and non-standard chains which may be in the system:

iptables -F && iptables -X

Install iptables-persistent so any iptables rules we make now will be restored on succeeding bootups. When asked if you want to save the current IPv4 and IPv6 rules, choose No for both protocols.

apt install iptables-persistent

Add IPv4 rules: iptables-persistent stores its rulesets in the files /etc/iptables/rules.v4 and /etc/iptables/rules.v6. Open the rules.v4 file and replace everything in it with the information below:

By default, OpenVPN runs as root. The user nobody given in the server.conf template has fewer privileges than root. If nobody gets compromised, the intruder will have access to processes running as the nobody user. This can include Apache when using mod_php, various NFS mounts and some cron jobs. Forcing OpenVPN to run as its own exclusive user and group is a good way to isolate it from other processes, especially if you will also be hosting a web or file server on the same host as your VPN.

Create a new user account and group for the OpenVPN daemon to run as after startup. The name ovpn is used as an example.

Require a matching HMAC signature for all packets involved in the TLS handshake between the server and connecting clients. Packets without this signature are dropped. To generate the HMAC signature file:

openvpn --genkey --secret /etc/openvpn/server/ta.key

Generate Diffie-Hellman parameter. This is a set of randomly generated data used when establishing Perfect Forward Secrecy during creation of a client’s session key. The default size is 2048 bits, but OpenVPN’s documentation recommends to use a prime size equivalent to your RSA key size. Since you will be using 4096 bit RSA keys, create a 4096 bit DH prime. Depending on the size of your Linode, this could take approximately 10 minutes to complete.

VPN Certificate Authority

Client certificates and keys should be not be managed directly on your VPN server. They should be created locally on a computer and stored offline. For the best quality entropy, they should be created on a computer which has a powerful CPU. You should avoid doing this on a virutal machine.

You can generate certificates and keys two ways: by using EasyRSA scripts, or by creating your own public key infrastructure for your VPN, which includes customizations not included in the default OpenSSL configuration file.

The rest of this guide will use EasyRSA.

Configure EasyRSA

If you’re using a local Unix-based operating system, install the package easy-rsa onto your local computer (CentOS will first need the EPEL repositories installed). For OS X or Windows, grab the .zip archive from the project’s Github repository.

Make your a root directory for the Certificate Authority. The location of your CA is arbitrary, but for the purposes of this guide make a folder called ca in your user’s home directory as an example. The certificates are created from that directory.

make-cadir ~/ca && cd ~/ca

Create a symbolic link from openssl-1.1.0.cnf to openssl.cnf:

ln -s openssl-1.0.0.cnf openssl.cnf

The vars file created in /ca contains presets used by EasyRSA. Here you can specify a distinguished name for your certificate authority that will be passed to client certificates. Changing these fields is optional, and you can always input them manually during certificate creation, but setting them here creates less work during client certificate creation.

~/ca/vars

123456789

# These are the default values for fields# which will be placed in the certificate.# Don't leave any of these fields blank.export KEY_COUNTRY="US"export KEY_PROVINCE="CA"export KEY_CITY="SanFrancisco"export KEY_ORG="Fort-Funston"export KEY_EMAIL="me@myhost.mydomain"export KEY_OU="MyOrganizationalUnit"

NOTE: If you run ./clean-all, I will be doing a rm -rf on /home/user/ca/keys

Run the clean-all script to create the keys directory and its containing files:

./clean-all

Server Credentials

A root certificate, sometimes called a Certificate Authority, is the certificate and key pair that will be used to generate key pairs for clients and intermediate authorities (on this VPN server there are none). At each prompt, add or edit the information to be used in your certificate, or leave them blank. Use your VPN server’s hostname or some other identifier as the Common Name and leave the challenge password blank.

./build-ca

Then create the server’s private key, add or edit the information prompts as needed:

./build-key-server server

When you’ve completed the question section for the private key, confirm the signing of the certificate and the certificate requests certified by answering yes to those two questions.

Upload the server credentials to your Linode, using scp from your local computer:

You’ll also want a copy of the HMAC key you created earlier to distribute to each client device:

scp root@<your_linode's_IP>:/etc/openvpn/server/ta.key ./keys

Client Credentials

Each client device connecting to the VPN should have its own unique key and identifier (client1, client2, etc.). All other certificate information can remain the same and be shared across all client devices. If you need to add users at any time later, just repeat this step using a different client name.

cd ~/ca && source ./vars && ./build-key client1

Note

Anyone with access to client1.key will be able to access your VPN. To better protect against this scenario, you can issue ./build-key-pass client1 instead to build a client key which is encrypted with a passphrase.

OpenVPN Configuration Files

Server Configuration File

OpenVPN’s server-side configuration file is /etc/openvpn/server.conf. Use the contents below to create a new file at that location on your server:

Client Configuration File

OpenVPN’s client-side configuration file is client.ovpn. When you import an OpenVPN profile, the location of the directory where the credentials are stored doesn’t matter, but this .ovpn file needs to be in the same directory as the client certificate and all other credentials. OpenVPN does not refer to any of these files after importing and they do not need to remain on the client system. Create this file on your Linode so that it can be distributed to your client devices:

Initial Startup and Log Monitoring

Start the OpenVPN daemon and enable it on reboot:

sudo systemctl enable openvpn.* && sudo systemctl start openvpn.*

Note

This will scan the /etc/openvpn directory on the server for files with a .conf extension. For every file that it finds, it will spawn a VPN daemon (server instance) so make sure you don’t have a client.conf or client.ovpn file in there.

The logs of both the OpenVPN client and servers will contain all the information you need to confirm connection specifications, view client address assignments, and debug connection issues. Even if the connection completes without problems, the logs may contain alerts and messages, to aid in improving your setup.

Use sudo journalctl -f | grep vpn to monitor the logs of your OpenVPN server in realtime; press Control+C to stop monitoring. The command sudo journalctl -xe | grep openvpn can also be useful for troubleshooting.

Next Steps

You should now have an operational OpenVPN server and a set of certificate/key pairs for your desired client devices. If you intend to use your OpenVPN server as an extension of your local network, or for hosting services you want to access from your LAN, you would need to configure the specific applications for your use.

More Information

You may wish to consult the following resources for additional information on this topic. While these are provided in the hope that they will be useful, please note that we cannot vouch for the accuracy or timeliness of externally hosted materials.