HowTo: Setup an OpenVPN Server

Reading Time: 8 minutes

This time, I would like to describe how I setup my OpenVPN server at home. I use this server to tunnel my traffic home, when using an open Wifi network at hotels or airports, to make sure, my traffic is encrypted. I also use the tunnel. to get access to my mail server when being at work, were only our corporate mail server is allowed to reach and all others are blocked.

OpenVPN is a software which makes it possible to tunnel traffic to a server. IT looks like you have a direct connection to this server and the network in between is totally transparent. Using the software, you have two options, L3 tunneling, which will route the traffic at the OpenVPN server to the destination or L2 tunneling, which will connect the VPN clients to the local network at the OpenVPN server site. I will explain, how to use both options.

You can use the software in a server-client topology, where regular clients will connect to the server or as a point-to-point connection to interconnect different sites which each other.

The connection is always encrypted using a certificate. This makes sure, that the traffic stays private on the way from the client to the server and vice versa.

Setup OpenVPN Server

I will install OpenVPN server on a ebian Jessi system. I will also install openssl on the system to generate the certificates for the server, which is mandatory for the server and optional for the clients.

The OS itself is already installed and I will not cover this in the post.

To install OpenVPN server and openssl on Debian Jessi, simply use this command:

apt-get install openvpn openssl easy-rsa

This will install the needed packages on Debian. I also installed easy-rsa, as this will make the creation of certificates much easier. This was the easy part. I will now create the needed certificates with openssl.

I need to change the directory to the easy-rsa directory in the OpenVPN directory:

cd /etc/openvpn/easy-rsa/

If the directory is not there, I can copy it over:

cp -R /usr/share/easy-rsa/* easy-rsa/

I need to make sure, that I’m already in the /etc/openvpn directory.

Next step is to modify the vars file in the easy-rsa directory:

vi vars

change the following lines to your needs:

export KEY_SIZE=2048
export KEY_COUNTRY="DE"
export KEY_PROVINCE="NRW"
export KEY_CITY="Haan"
export KEY_ORG="flomain.local"
export KEY_EMAIL="[email protected]"
export KEY_OU="flomain.local"

To export the settings and use them during certificate creation I will execute the vars file:

./vars

To remove old certificates and configurations I will run this command:

./clean-all

The next step is to generate the ca. One site node here. Never send .key files using insecure communication protocols. Keep it secure and save.

I create the CA using this command:

./build-ca

This will create the files needed for the ca to sign certificates. The files creates are the following ones:

  • ca.crt
  • ca.key

I will create a certificate for the OpenVPN server using this command:

./build-key-server infrastructure.flomain.local

This will generate the server certificate which is used by the OpenVPN server. The files are those ones:

  • infrastructure.flomain.local.crt
  • infrastructure.flomain.local.csr
  • infrastructure.flomain.local.key

To work properly, the OpenVPN server needs a DIFFIE-HELLMAN parameter file which will be created using this command:

./build-dh

This will create this file:

  • dh2048.pem

The last step is to create the certificates for the clients:

./build-key client.flomain.local

This needs to be done for every client and will create those files:

  • client.flomain.local.crt
  • client.flomain.local.csr
  • client.flomain.local.key

The following files needs to be copied over to the client:

  • ca.crt
  • client.flomain.local.crt
  • client.flomain.local.key

As the certificates are in place, the next step is to create the server and client configuration files.

L3 OpenVPN Server

I will start with the easy option. The L3 tunnel is easier to implement as there is no need to change something in the infrastructure. For a small setup like mine, I will use NAT to make the VPN clients even more transparent to my home network. The l3 type of tunnel is from my point of view the default requirement and should be enough for 90% of the cases.

I will create the server config first. I will create a new file in the /etc/openvpn directory. The “.conf” ending is important for OpenVPN to recognize this as a config file:

/etc/openvpn# vi server_l3.conf

The content of the file looks like this:

# Port
port 1194

# TCP oder UDP?
proto tcp-server
mode server
tls-server

#tun or tap device
#tun is an IP tunnel,
#tap an ethernet tunnel
dev tun

#Our Server IP
server 10.0.0.0 255.255.255.0

#Paths to the certs
ca /etc/openvpn/easy-rsa/keys/ca.crt
cert /etc/openvpn/easy-rsa/keys/infrastructure.flomain.local.crt
key /etc/openvpn/easy-rsa/keys/infrastructure.flomain.local.key

#Diffie-Hellmann Parameters
dh /etc/openvpn/easy-rsa/keys/dh2048.pem


cipher AES-256-CBC
tls-cipher TLS-DHE-RSA-WITH-AES-256-GCM-SHA384
tls-version-min 1.2
remote-cert-tls client

#Tests the connection with a ping like paket. (wait=120sec)
keepalive 10 120

#Authenication
auth SHA512

#comp
comp-lzo

#Sets new rights after the connection
user nobody
group nogroup

#We need this because of user nobody/group nobody.
persist-key
persist-tun

#Logging 0, (testing:5)
verb 0

The config file is very simple. I use tcp as the transport protocol, as I have issues with upd when at the office. I need to use the created certificates for the server and set a not used IP subnet for the server IP subnet. This IP subnet will be used by the server and the client to communicate with each other. The clients will also get IP address from this subnet from the OpenVPN server.

The client file looks simple as well:

client

float

dev tun

#tcp oder udp 
proto tcp-client

remote infrastructure.flomain.local 1194


ca ca.crt
cert client.flomain.local.crt
key client.flomain.local.key

cipher AES-256-CBC
tls-cipher TLS-DHE-RSA-WITH-AES-256-GCM-SHA384
tls-version-min 1.2


verify-x509-name infrastructure.flomain.local name

remote-cert-tls server

route 89.163.185.210 255.255.255.255
route 89.163.185.211 255.255.255.255
route 89.163.185.212 255.255.255.255
route 89.163.185.213 255.255.255.255
route 89.163.185.214 255.255.255.255
route 192.168.2.0 255.255.255.0

auth SHA512

nobind 
comp-lzo 
persist-key 
persist-tun 
verb 1

The client config contains the necessary certificate entries and some individual routing entries. The individual routing entries will make sure, that traffic to those destinations will be routed through the tunnel. All other traffic will use the normal default gateway configured on the client.

To use the tunnel to redirect all traffic through the tunnel the individual routing entries can be removed and this entry needs to be added:

redirect-gateway

If everything is working correctly, the client can connect to the server. Unfortunately, communication with other destinations then the server itself will fail, as the OpenVPN server is not able to route traffic. Let’s make sure, this will happen as well.

To enable routing on a Debian system use this command:

echo 1 > /proc/sys/net/ipv4/ip_forward

This will enable routing until the next system restart. To make it permanent I need to uncomment

net.ipv4.ip_forward = 1

in

/etc/sysctl.conf

This will make sure, that routing is enabled after the next system restart.

If the network is aware that VPN clients can be reached using the OpenVPN server, the clients are now able to use the connection. As I would like to NAT the clients to the IP of the OpenVPN server I need to tell the Debian system to do so:

iptables -t nat -A POSTROUTING -s 10.0.0.0/24 -o eth0 -j MASQUERADE

This will instruct the system to map every packet from the 10.0.0.0/24 subnet to the IP address of the eth0 interface.

To make this permanent I need to save the iptables to a file:

iptables-save > /etc/iptables.up.rules

To load the rules on startup use a script like this:

#!/bin/sh

iptables-restore < /etc/iptables.up.rules

and put it into this file:

/etc/network/if-pre-up.d/iptables

This will make sure, that the NAT instruction is loaded after a system reboot.

L2 OpenVPN Server

Now, I will get to the tricky part. It took me more than two weeks to get this working correctly. The l2 tunnel is not needed that often. To be honest, I only tested it, because I wanted to get it working. A real requirement for the l2 tunnel would be the use of a protocol which cannot be routed, like Apple airplay or airprint.

On ESXi, the vswitch needs to run in promiscuous mode to make this work, as the vswitch did not learn mac addresses like normal switches. From my point of view, they even did not lean mac addresses at all, they simply get the information about the mac address from the ESXi server.

Enable promiscuous mode for a vm network by setting promiscuous mode to accept:

Set-Promiscuous-Mode-for-VM-Network
Set-Promiscuous-Mode-for-VM-Network

For KVM/Proxmox, it is not necessary to to something like this.

To create a bridged tunnel, the first step is to create the bridge itself. To do so, bridge-utils is needed on Debian:

apt-get install bridge-utils

The next step, is to create the bridge. Open the following file:

vi /etc/network/interfaces

Assuming, there is only one network interface in the server, the file needs to be changed to look like this:

# This file describes the network interfaces available on your system
# and how to activate them. For more information, see interfaces(5).

source /etc/network/interfaces.d/*

# The loopback network interface
auto lo br0
iface lo inet loopback

# The primary network interface
allow-hotplug eth0
iface eth0 inet manual

allow-hotplug tap0
iface tap0 inet manual

iface br0 inet static
 address 192.168.2.22
 netmask 255.255.255.0
 network 192.168.2.0
 broadcast 192.168.2.255
 gateway 192.168.2.1
 search-domain flomain.local
 bridge_ports eth0 tap0
 pre-up openvpn --mktun --dev tap0
 post-down openvpn --rmtun --dev tap0

There are two new interfaces created. The tap0 interface will be used by the OpenVPN server. The br0 interface is the bridge, which will bring eth0 and tap0 together. The result will be, that all clients, connected to the OpenVPN server, will be placed in the same network as eth0.

As all clients will be in the same network as the server, there are two options to provide IP addresses to the clients. OpenVPN will provide IP addresses to the clients and act as the DHCP server. If choosing this option, the local DHCP server needs to be aware of this and should exclude the range, which is provided by the OpenVPN server to avoid duplicate IP addresses.

The second option is to use the local DHCP server to provide IP addresses to VPN clients as well. If choosing this option, the local DHCP server needs to be aware of VPN clients and remove the option for the gateway for VPN clients on the DHCP answers. This is very important. Ignoring this will lead to a non functional environment.

I have chosen the second option and my OpenVPN server config for this option looks like this:

# Port
port 1194

# TCP oder UDP?
proto udp
mode server
tls-server

#tun or tap device
#tun is an IP tunnel,
#tap an ethernet tunnel
dev tap0

#Paths to the certs
ca /etc/openvpn/easy-rsa/keys/ca.crt
cert /etc/openvpn/easy-rsa/keys/infrastructure.flomain.local.crt
key /etc/openvpn/easy-rsa/keys/infrastructure.flomain.local.key

#Diffie-Hellmann Parameters
dh /etc/openvpn/easy-rsa/keys/dh2048.pem


cipher AES-256-CBC
tls-cipher TLS-DHE-RSA-WITH-AES-256-GCM-SHA384
tls-version-min 1.2
remote-cert-tls client

client-to-client


#Tests the connection with a ping like paket. (wait=120sec)
keepalive 10 120

#Authenication
auth SHA512

push "route-gateway 192.168.2.1"
push "redirect-gateway def1"

#comp
comp-lzo

#Sets new rights after the connection
user nobody
group nogroup

#We need this because of user nobody/group nobody.
persist-key
persist-tun

#Logging 0, (testing:5)
verb 0

The configuration looks similar the one used for the l3 tunnel. The main differences are the use of UDP instead of TCP (I use TCP for the l3 tunnel because UDP is blocked at my office), the use of the previously created tap0 interface, client to client communication is allowed, which makes sense as they are in the same network and the push commands, which tell the client to use the local gateway at the OpenVPN server site.

Why should this push method be used to provide the default gateway to the client instead of using the DHCP method? when using your local DHCP server, the routing table of the client will have a second entry for the default route, but with a much higher metric. This will cause, that this path is never used and no traffic will go through the tunnel. When using the push method for the gateway, OpenVPN will create two routes at the client. One for 0.0.0.0/128.0.0.0 and a second one for 128.0.0.0/128.0.0.0. Both will have a higher metric as the default route, but as the smallest route always win, the /128.0.0.0 netmask will make the difference. This is heavily important and it took me more than a week to figure this out.

To use the OpenVPN server for DHCP instead of the local DHCP server, insert this directive to the configuration:

server-bridge 192.168.1.10 255.255.255.0 192.168.1.100 192.168.1.110

192.168.1.10 would be the IP of the OpenVPN server in the local network and the range from 100-110 the scope for the OpenVPN clients.

The client configuration looks like this:

#this is the client
client

dev tap

#tcp oder udp 
proto udp

remote infrastructure.flomain.loal 1194

ca ca.crt
cert arbeitslaptop.flomain.local.crt
key arbeitslaptop.flomain.local.key

cipher AES-256-CBC
tls-cipher TLS-DHE-RSA-WITH-AES-256-GCM-SHA384
tls-version-min 1.2

verify-x509-name infrastructure.flomain.local name

remote-cert-tls server

auth SHA512

nobind 
comp-lzo 
persist-key 
persist-tun 
verb 0

The config looks pretty strait. The same changes as for the server configuration, moving from tun to tap and from TCP to UDP.

From here, everything should work fine and even if I’m abroad, I can enjoy my local TV shows from home.

If you have any questions, regarding this post or if you would like to provide feedback, please use the comment function below.

Leave a Reply

This site uses Akismet to reduce spam. Learn how your comment data is processed.