Create a VPN server with OpenVPN

OpenVPN is an open-source, cross-platform software package to run a VPN server and secure connections over the internet. Because the source is freely available, you can be assured that there are no built-in backdoors or wiretap capabilities in it. Both the Client and the Server software are available for multiple platforms, including Linux, Windows, MacOSX, and various embedded devices like network routers.

In addition to username / password authentication, OpenVPN supports multiple authentication methods to implement MFA – you can find more information about multi-factor authentication here: Protect your online accounts with multi-factor authentication.

How do VPNs work?

VPN software opens a tunnel between your own (client) computer and the VPN server. Any network traffic between the two machines is securely encrypted and cannot be eavesdropped on.

As long as the VPN is active, from the outside world’s point of view, any traffic that’s routed through the VPN appears as it was coming from the server, hiding the real identity of the client. If the VPN server has access to private networks, this is a way to securely connect remote clients to that private network without compromising the security of it.

Installing OpenVPN server on Debian

To install OpenVPN server, you simply need to run the command

# apt-get install openvpn

this will not configure it yet but install as a service. To make it functional, we need to create a server config file first.

In OpenVPN, each server instance is defined by a config file under /etc/openvpn. On startup, it scans the directory for conf files and it will start an instance for each.

Configure OpenVPN startup

To enable automatic starting of any instance defined under /etc/openvpn, you’ll need to edit /etc/default/openvpn and change the “AUTOSTART” line to “ALL” instead of none:

# This is the configuration file for /etc/init.d/openvpn

#
# Start only these VPNs automatically via init script.
# Allowed values are "all", "none" or space separated list of
# names of the VPNs. If empty, "all" is assumed.
# The VPN name refers to the VPN configutation file name.
# i.e. "home" would be /etc/openvpn/home.conf
#
# If you're running systemd, changing this variable will
# require running "systemctl daemon-reload" followed by
# a restart of the openvpn service (if you removed entries
# you may have to stop those manually)
#
AUTOSTART="all"
#AUTOSTART="none"
#AUTOSTART="home office"
...

To reload configuration, do a systemctl daemon-reload and then service openvpn restart should reload the configuration and start openvpn instances. Any time a new config file is created or removed, this step should repeated to activate those changes.

Server configuration

In its simplest configuration, OpenVPN can be configured to authenticate using a static key. This way there is no requirement for usernames/passwords and security is provided by the pre-shared secure key that should be present both on the server and the client. This is a great way to test OpenVPN functionality before proceeding to more complicated configurations.

The first step of this is to generate an OpenVPN static key that we’ll use for authentication. Let’s put this into /etc/openvpn:

# openvpn --genkey --secret static.key
# cat static.key 
#
# 2048 bit OpenVPN static key
#
-----BEGIN OpenVPN Static key V1-----
877a92fa96102b84b5ce49e1d582f853
f6897d7418e0bd0d1948331137c5cf44
1834a44e03bf1dcc3e44f58fd63a96d0
ff3c95f3b3e6c57312428458d09aaa69
851877fb2f0da5e0997c427e836850e6
1b0ee300e71091ce3399660ac5807209
...

This will be the key that should be securely shared between the client and the server.

The server configuration is only a few lines, to define the static key and the IP range the server is going to define for a client.

dev tun
ifconfig 10.8.0.1 10.8.0.2
secret static.key
cipher AES-256-CBC 

The ifconfig line defines the local/remote IP address of the VPN connection, the secret defines the pre-shared secret key we’ve just generated and cipher sets a secure cipher because the default one is not considered secure anymore.

To start the server, run this command – it will for now stay in the foreground – it’s useful for debugging, later we’ll start this using init scripts (see above).

# openvpn --config server.conf 
Fri May 21 08:22:56 2021 disabling NCP mode (--ncp-disable) because not in P2MP client or server mode
Fri May 21 08:22:56 2021 OpenVPN 2.4.7 x86_64-pc-linux-gnu [SSL (OpenSSL)] [LZO] [LZ4] [EPOLL] [PKCS11] [MH/PKTINFO] [AEAD] built on Feb 20 2019
Fri May 21 08:22:56 2021 library versions: OpenSSL 1.1.1d  10 Sep 2019, LZO 2.10
Fri May 21 08:22:56 2021 TUN/TAP device tun0 opened
Fri May 21 08:22:56 2021 /sbin/ip link set dev tun0 up mtu 1500
Fri May 21 08:22:56 2021 /sbin/ip addr add dev tun0 local 10.8.0.1 peer 10.8.0.2
Fri May 21 08:22:56 2021 Could not determine IPv4/IPv6 protocol. Using AF_INET
Fri May 21 08:22:56 2021 UDPv4 link local (bound): [AF_INET][undef]:1194
Fri May 21 08:22:56 2021 UDPv4 link remote: [AF_UNSPEC]

OpenVPN client configuration

On the client side, the configuration will look like this:

remote server.ip.address
dev tun
ifconfig 10.8.0.2 10.8.0.1
secret static.key
cipher AES-256-CBC 

The lines are similar to the server configuration, IP addresses are reversed in the “ifconfig” line, the “remote” line should contain the IP address or DNS name of the server and “cipher” should match what it is on the server.

To connect, run OpenVPN just like you did on the server and it will automatically set up the VPN and connect to it. You’ll need to be root or administrator to do this because it needs to set up routes. This example below was MacOSX client that’s installable using “brew” or part of the “TunnelBlick” GUI app. The same thing would work on Linux or Windows, once OpenVPN is installed from here: https://openvpn.net.

# openvpn --config client.conf
Fri May 21 08:26:50 2021 OpenVPN 2.3.6 x86_64-apple-darwin [SSL (OpenSSL)] [LZO] [PKCS11] [MH] [IPv6] built on Sep 19 2015
Fri May 21 08:26:50 2021 library versions: OpenSSL 1.0.1p 9 Jul 2015, LZO 2.08
Fri May 21 08:26:50 2021 WARNING: file 'static.key' is group or others accessible
Fri May 21 08:26:50 2021 Opening utun (connect(AF_SYS_CONTROL)): Resource busy
Fri May 21 08:26:50 2021 Opened utun device utun1
Fri May 21 08:26:50 2021 do_ifconfig, tt->ipv6=0, tt->did_ifconfig_ipv6_setup=0
Fri May 21 08:26:50 2021 /sbin/ifconfig utun1 delete
ifconfig: ioctl (SIOCDIFADDR): Can't assign requested address
Fri May 21 08:26:50 2021 NOTE: Tried to delete pre-existing tun/tap instance -- No Problem if failure
Fri May 21 08:26:50 2021 /sbin/ifconfig utun1 10.8.0.2 10.8.0.1 mtu 1500 netmask 255.255.255.255 up
Fri May 21 08:26:50 2021 UDPv4 link local (bound): [undef]
Fri May 21 08:26:50 2021 UDPv4 link remote: [AF_INET]x.x.x.x:1194
Fri May 21 08:27:00 2021 Peer Connection Initiated with [AF_INET]x.x.x.x:1194
Fri May 21 08:27:01 2021 Initialization Sequence Completed

Aaaand we’re done, simple as that. Various GUI based OpenVPN clients exist to make connecting to OpenVPN servers easier. On Windows, config files should have a .ovpn extension – double clicking them automatically starts OpenVPN with the right config file (openvpn –config client.ovpn).

Security considerations

The following example implements a simple shared key authentication. OpenVPN is capable of authentication using usernames/password pairs, certificates, and pretty much any PAM module and script, including Google Authenticator style 2FA codes.

In the next article, we’ll look at the more advanced uses and routing examples, like how to route internet traffic through the VPN server and how to secure services on the server to make them accessible through VPN only.

Related Posts