Setting up an OpenVPN access server

This post is strictly geeky stuff so feel free to skip and check out the poetry and short stories instead (don’t leave until you do! Thanks!)

A friend/colleague contacted me a couple of days ago and asked if I know how to set up an OpenVPN server. He said he took a look at the website (openvpn.net) and that the instructions there are not that easy to follow. Nothing challenges me more than getting IT-related stuff to work – figuring stuff out. And also, he said there might be some $$ involved.
I knew what OpenVPN was but had never set up a server before. It took 2 days and nights to figure the stuff out completely. One thing I don’t like is having to repeat the same process for the same thing in future, so I almost always “document” the procedure(s).

Once it is nicely summarized (as below), it then looks quite easy, but it is not! (stroking my own ego a little :-).

Let’s go!

Setting up an OpenVPN access server on Linux (with a Windows Client)

1. Install Open-VPN server
NOTE: The /etc/init.d/openvpn service control script comes from the openvpn-AS server package but it’s easy
to create one. I have attached a copy (should be in the same directory as this howto)

# yum install openssl-devel lzo-devel pam-devel
# yum install rpm-build
# rpmbuild -tb openvpn-2.4.0.tar.gz
# rpm -Uvh /root/rpmbuild/RPMS/x86_64/openvpn-2.4.0-1.x86_64.rpm

2. Copy or create /etc/init.d/openvpn (so you can use the service command to control the service)

3. Install/download EasyRSA for creating the CA (Ceritification Authority) as well as certificates for clients:

download scripts package from https://github.com/OpenVPN/easy-rsa

cd /tmp
unzip easy-rsa-master.zip
cp -R /tmp/easy-rsa-master/easyrsa3 /etc/openvpn/

4. Copy the sample config files folder to /etc/openvpn
cp /usr/share/doc/openvpn-2.4.0/sample/sample-config-files/server.conf /etc/openvpn/
cp /usr/share/doc/openvpn-2.4.0/sample/sample-config-files/client.conf /etc/openvpn/
cp /usr/share/doc/openvpn-2.4.0/sample/sample-config-files/openvpn-startup.sh /etc/openvpn/openvpn-startup
cp /usr/share/doc/openvpn-2.4.0/sample/sample-config-files/openvpn-shutdown.sh /etc/openvpn/openvpn-shutdown

5. You should edit openvpn-shutdown and change the line “killall -TERM openvpn” to “killall -TERM /usr/sbin/openvpn”
(reason is that when you use “service openvpn restart|shutdown”, killall kills the service command as well)

6. You have to edit the server.conf to reflect the location of files relative to the /etc/opevpn folder.
For example, the entry “dh dh2048.pem” in server.conf needs to reflect where you actually put the dh2048.pem file.
If you put the files directly in /etc/openvpn then nothing needs to change, but if you decide for management
purposes to put the file in a subfolder (e.g., in /etc/openvpn/keys/ then the entry in server.conf would be “dh keys/dh2048.pem”) the entries would have to change. Same applies to entries for “ca”, “cert”, and “key”.

7. This option in server.conf is to protected against DDoS (either follow the instructions or comment it out)
tls-auth ta.key 0 # This file is secret

8. The 3 lines below are at the bottom of file openvpn-startup. Comment them out or create the vpn*.conf files.
I don’t think they are needed unless you have a need to have deamons with different configs e.g., say a deamon for different companies connecting to your server.
openvpn –cd $dir –daemon –config vpn1.conf
openvpn –cd $dir –daemon –config vpn2.conf
openvpn –cd $dir –daemon –config vpn2.conf

9. Creating the various certificates:

# cd /etc/openvpn/easyrsa3/

[root@gfs2 easyrsa3]# cp vars.example vars

10. Edit the vars file and set the following variables according to your needs:

[root@gfs2 easyrsa3]# vi vars

set_var EASYRSA_REQ_COUNTRY “NG”
set_var EASYRSA_REQ_PROVINCE “LA”
set_var EASYRSA_REQ_CITY “Lagos”
set_var EASYRSA_REQ_ORG “Samson Inc.”
set_var EASYRSA_REQ_EMAIL “sam@company.net”
set_var EASYRSA_REQ_OU “IT Organizational Unit”
set_var EASYRSA_REQ_CN=gfs2.company.com
set_var EASYRSA_REQ_NAME=server

[root@gfs2 easyrsa3]#

11. Initialize the PKI (you only need to do this once for a fresh setup):

[root@gfs2 easyrsa3]# ./easyrsa init-pki

12. Create the CA:
Answer 2 questions below (Common Name e.g., the name of the server, and the PEM passphrase – use any phrase)

[root@gfs2 easyrsa3]# ./easyrsa build-ca

13. Remove the passphrase (because we are running openvpn daemon non-interactively so no way to enter the phrase)
You will be prompted for the same passphrase you entered above when creating the certificate:

# cd /etc/openvpn/easyrsa3/pki/private
# openssl rsa -in ca.key -out ca.key2
[root@gfs2 private]# mv ca.key ca.key.org
[root@gfs2 private]# mv ca.key2 ca.key
[root@gfs2 private]# cd /etc/openvpn/easyrsa3/

14. Generate the Diffie hellman parameters (DH):
[root@gfs2 easyrsa3]# ./easyrsa gen-dh

15. Generate the CRL:
[root@gfs2 easyrsa3]# ./easyrsa gen-crl

16. Generate a certificate for the server (use any passphrase. We will remove it):
In the example below, gfs2 is the name of my server.

[root@gfs2 easyrsa3]# ./easyrsa build-server-full gfs2
# cd /tmp/easy-rsa-master/easyrsa3/pki/private/
# openssl rsa -in gfs2.key -out gfs2.key2
# mv gfs2.key gfs2.key.org
# mv gfs2.key2 gfs2.key

17. Copy all the files to your /etc/openvpn/ folder
[root@gfs2 easyrsa3]# cd /etc/openvpn/
[root@gfs2 openvpn]# cp easyrsa3/pki/crl.pem .
[root@gfs2 openvpn]# cp easyrsa3/pki/dh.pem .
[root@gfs2 openvpn]# cp easyrsa3/pki/ca.crt .
[root@gfs2 openvpn]# cp easyrsa3/pki/private/ca.key .
[root@gfs2 openvpn]# cp easyrsa3/pki/private/gfs2.key .
[root@gfs2 openvpn]# cp easyrsa3/pki/issued/gfs2.crt .
[root@gfs2 openvpn]# cp easyrsa3/pki/ca.crt /etc/openvpn/clients/

18. Edit server.conf in /etc/openvpn/ and make the necessary changes. The 3 lines in server.conf show below reflects the files created above:
ca ca.crt
cert gfs2.crt
key gfs2.key

19. Generate certificates for your clients (repeat for various clients using unique names in the process):
You will be prompted for a passphrase. Use any, we will remove it. In the example below, remoteclient1 is the name of a unique CN (Common Name) I am using for a client. Note that this does not have to be the actual name on the client.
But it is this name you will enter in the configuration of your VPN client on your remote client. This will then
allow the OpenVPN server to match the name to a specific configuration (if any) and client certificates on the server.

# cd /etc/openvpn/easyrsa3
[root@gfs2 easyrsa3]# ./easyrsa build-client-full remoteclient1
[root@gfs2 easyrsa3]# cd pki/private/

20. Remove the passphrase on the certificate (you will be prompted for the same passphrase you used above):
[root@gfs2 private]# openssl rsa -in remoteclient1.key -out remoteclient1.key2
[root@gfs2 private]# mv remoteclient1.key remoteclient1.key.org
[root@gfs2 private]# mv remoteclient1.key2 remoteclient1.key
[root@gfs2 private]# cp remoteclient1.key /etc/openvpn/clients/
[root@gfs2 private]# cp ../issued/remoteclient1.crt /etc/openvpn/clients/

21. Copy/Send the necessary certificates to the client (should be done as securely as possible)
ca.crt, remoteclient1.crt and remoteclient1.key (for my sample client)

22. On my sample Windows client. I am using SecurePoint SSL VPN v2
– I downloaded version 2.0.18 from https://sourceforge.net/projects/securepoint/
– Install it and run it.
– In the system-tray, right-click on the icon and choose “show window” from the menu
– Click on the settings icon (gear wheel in the lowe right-hand corner of the application window) and choose “New” fro the menu.
– Follow the wizard to create a new VPN connection.
– give the config a name; next;
– enter the IP address of FQDN of the VPN access server and change the port and protocol if necessary (must match the one on the server as defined in server.conf); next
– you are prompted for the location of 3 files you transferred to the client above: “Root CA:”; “Certificate:”; and “Key:”
“Root CA:” = ca.crt; “Certificate:” = remoteclient1.crt; and “Key:” = remoteclient1.key
– the “Advanced Settings” screen is next. IMPORTANT: You have to change the cipher (defaul is “Standard”) to the one configured in the server.conf file on the VPN access server. Current default is AES-256-CBC. If you don’t change it, you will still get connected but no real traffic will flow over the VPN (you won’t get any service or connectivity). You can also “Comp-LZO” compression; next
– Conclusion screen shows you a summary of your choices. Click the “Finish” button if everything looks OK
– Your new VPN connection config will appear in the Window of the VPN client. Right-click on it and choose “Connect”
– The next 2 screens will ask for your username and password. Both answers are the name of the client we used to create the certificate which is remoteclient1. You can also select the “Save Data” on both questions to have the VPN client remember your answers.
– The VPN connection to the server should be established once you press OK for the 2 questions above.

23. Suggested optional step: to configure OpenVPN to log into it’s own log file and not /var/log/messages (especially if you are debugging issues.)
Edit server.conf and change the log-append line (it is likely to be commented out. So remove the “;” at the begining of the line).

log-append /var/log/openvpn.log

24. Optionally install Web-pased connection monitor

– Download it from https://github.com/furlongm/openvpn-monitor/

– You need to install the semanticversion package to run the openvpn-monitor successfully

– Use pip to install the semantic_version package:
# yum install python-pip
# pip install semantic_version

Alternatively if for some reason you can’t install pip, you can install the semantic_version “manually” with python:

# cd /tmp
# git clone git://github.com/rbarrois/python-semanticversion.git
# cd python-semanticversion
# python setup.py install

– Then continue with installation instructions on the openvpn-monitor webpage above (start from the section for your Operating System)

NOTE: on RHEL/CentOS 6.x, you may need to edit /var/www/html/openvpn-monitor/openvpn-monitor.conf and enter the coordinates of your starting point (probably the location of your server). You can get the “DD coordinates” (for longitude and latitude) for your location (I was able to get the coords for my campus) from http://latitude.to/ for example. You can also try https://www.distancesto.com/coordinates.php

25. Restart (start) the OpenVPN service (any errors will be in file /var/log/messages)
# service openvpn restart

– – – – – – – – – – – – – – – – – – – – – – – – – – – – – – – – – – – – – – – – – – –
NOTES:

1. You may need to enable ipv4 forwarding if you want the remote clients to connect to other systems on the network of the VPN access server. The community version seems to do this by default but not sure of the commercial version (“sysctl -w net.ipv4.ip_forward=1” )
You will also need to edit server.conf and use the “push route” option so that the routes to (private) subnets “behind” the VPN server is sent to the clients if required (so the clients can reach other systems on those private subnets)

2. GUI for OpenVPN server on Windows:
download from https://github.com/OpenVPN/openvpn-gui

3. Alternative GUI-based way to control OpenVPN via Webmin module. Not worth the trouble as the developer’s website is not in English and not sure how up to date the module is. Not recommended.

yum install perl
yum install perl-Net-SSLeay
wget http://prdownloads.sourceforge.net/webadmin/webmin-1.831-1.noarch.rpm
rpm -Uvh wget webmin-1.831-1.noarch.rpm
download openvpn-2.6.wbm.gz from http://www.openit.it/index.php/it/openvpnadmin and use Webmin to install it.
The module can generate certificates but I found it much more troublesome than the direct approach I used above.

4. There are various other options you may need to change in server.conf (and which must match on the client as well) to further optimize your setup.

5. Systems used in the config above (3x VMs running on VMWare workstation 12.5.2 on a HP EliteBook 840 – Windows 7, 16GB RAM, Intel Core i7 vPro):
a. Red Hat Enterprise Linux Server release 6.3 – OpenVPN 2.4.0 access server
b. Windows 8 (VPN client)
c. Windows XP (system “behind” VPN server on a private subnet)

6. Some other install guide:
http://www.ciscopress.com/articles/article.asp?p=605499
https://help.ubuntu.com/lts/serverguide/openvpn.html
https://openvpn.net/index.php/open-source/documentation/howto.html#security
https://openvpn.net/index.php/access-server/docs/quick-start-guide.html
https://openvpn.net/index.php/open-source/documentation/howto.html#install
https://www.digitalocean.com/community/tutorials/how-to-setup-and-configure-an-openvpn-server-on-centos-6

7. There several other clients for Windows, MAC, etc on the Internet. Some are free (open source/closed-source) and some are commercial/proprietary. Each has it’s own idiosyncrasies. I found it difficult getting the OpenVPN client to work with the OpenVPN server I set up above, but it worked seamlessly with their own OpenVPN AS VPN server (the commercial version of the OpenVPN server that comes with a management GUI).

8. Keywords or Tags: PKI,SecurePoint,OpenVPN,VPN,Diffie hellman,EasyRSA,RedHat,rpmbuild,github,Linux

9. The content of the /etc/init.d/openvpn service control script. You can add the service to run-levels 345 so it starts automatically whenever you (re)start the server (command “chkconfig –add openvpn”).

#!/bin/sh
#
# openvpn This shell script takes care of starting and stopping
# openvpn on RedHat or other chkconfig-based system.
#
# chkconfig: 345 24 76
#
# description: OpenVPN is a robust and highly flexible tunneling application \
# that uses all of the encryption, authentication, and \
# certification features of the OpenSSL library to securely \
# tunnel IP networks over a single UDP port.
#

# Contributed to the OpenVPN project by
# Douglas Keller <doug_at_voidstar.dyndns.org>
# 2002.05.15

# To install:
# copy this file to /etc/rc.d/init.d/openvpn
# shell> chkconfig –add openvpn
# shell> mkdir /etc/openvpn
# make .conf or .sh files in /etc/openvpn (see below)

# To uninstall:
# run: chkconfig –del openvpn

# Author’s Notes:
#
# I have created an /etc/init.d init script and enhanced openvpn.spec to
# automatically register the init script. Once the RPM is installed you
# can start and stop OpenVPN with “service openvpn start” and “service
# openvpn stop”.
#
# The init script does the following:
#
# – Starts an openvpn process for each .conf file it finds in
# /etc/openvpn.
#
# – If /etc/openvpn/xxx.sh exists for a xxx.conf file then it executes
# it before starting openvpn (useful for doing openvpn –mktun…).
#
# – In addition to start/stop you can do:
#
# service openvpn reload – SIGHUP
# service openvpn reopen – SIGUSR1
# service openvpn status – SIGUSR2
#
# Modifications:
#
# 2003.05.02
# * Changed == to = for sh compliance (Bishop Clark).
# * If condrestart|reload|reopen|status, check that we were
# actually started (James Yonan).
# * Added lock, piddir, and work variables (James Yonan).
# * If start is attempted twice, without an intervening stop, or
# if start is attempted when previous start was not properly
# shut down, then kill any previously started processes, before
# commencing new start operation (James Yonan).
# * Do a better job of flagging errors on start, and properly
# returning success or failure status to caller (James Yonan).
#
# 2005.04.04
# * Added openvpn-startup and openvpn-shutdown script calls
# (James Yonan).
#

# Location of openvpn binary
openvpn=””
openvpn_locations=”/usr/sbin/openvpn /usr/local/sbin/openvpn”
for location in $openvpn_locations
do
if [ -f “$location” ]
then
openvpn=$location
fi
done

# Lockfile
lock=”/var/lock/subsys/openvpn”

# PID directory
piddir=”/var/run/openvpn”

# Our working directory
work=/etc/openvpn

# Source function library.
. /etc/rc.d/init.d/functions

# Source networking configuration.
. /etc/sysconfig/network

# Check that networking is up.
if [ ${NETWORKING} = “no” ]
then
echo “Networking is down”
exit 0
fi

# Check that binary exists
if ! [ -f $openvpn ]
then
echo “openvpn binary not found”
exit 0
fi

# See how we were called.
case “$1″ in
start)
echo -n $”Starting openvpn: ”

/sbin/modprobe tun >/dev/null 2>&1

# From a security perspective, I think it makes
# sense to remove this, and have users who need
# it explictly enable in their –up scripts or
# firewall setups.

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

# Run startup script, if defined
if [ -f $work/openvpn-startup ]; then
$work/openvpn-startup
fi

if [ ! -d $piddir ]; then
mkdir $piddir
fi

if [ -f $lock ]; then
# we were not shut down correctly
for pidf in `/bin/ls $piddir/*.pid 2>/dev/null`; do
if [ -s $pidf ]; then
kill `cat $pidf` >/dev/null 2>&1
fi
rm -f $pidf
done
rm -f $lock
sleep 2
fi

rm -f $piddir/*.pid
cd $work

# Start every .conf in $work and run .sh if exists
errors=0
successes=0
for c in `/bin/ls *.conf 2>/dev/null`; do
bn=${c%%.conf}
if [ -f “$bn.sh” ]; then
. ./$bn.sh
fi
rm -f $piddir/$bn.pid
$openvpn –daemon –writepid $piddir/$bn.pid –config $c –cd $work
if [ $? = 0 ]; then
successes=1
else
errors=1
fi
done

if [ $errors = 1 ]; then
failure; echo
else
success; echo
fi

if [ $successes = 1 ]; then
touch $lock
fi
;;
stop)
echo -n $”Shutting down openvpn: ”
for pidf in `/bin/ls $piddir/*.pid 2>/dev/null`; do
if [ -s $pidf ]; then
kill `cat $pidf` >/dev/null 2>&1
fi
rm -f $pidf
done

# Run shutdown script, if defined
if [ -f $work/openvpn-shutdown ]; then
$work/openvpn-shutdown
fi

success; echo
rm -f $lock
;;
restart)
$0 stop
sleep 2
$0 start
;;
reload)
if [ -f $lock ]; then
for pidf in `/bin/ls $piddir/*.pid 2>/dev/null`; do
if [ -s $pidf ]; then
kill -HUP `cat $pidf` >/dev/null 2>&1
fi
done
else
echo “openvpn: service not started”
exit 1
fi
;;
reopen)
if [ -f $lock ]; then
for pidf in `/bin/ls $piddir/*.pid 2>/dev/null`; do
if [ -s $pidf ]; then
kill -USR1 `cat $pidf` >/dev/null 2>&1
fi
done
else
echo “openvpn: service not started”
exit 1
fi
;;
condrestart)
if [ -f $lock ]; then
$0 stop
# avoid race
sleep 2
$0 start
fi
;;
status)
if [ -f $lock ]; then
for pidf in `/bin/ls $piddir/*.pid 2>/dev/null`; do
if [ -s $pidf ]; then
kill -USR2 `cat $pidf` >/dev/null 2>&1
fi
done
echo “Status written to /var/log/messages”
else
echo “openvpn: service not started”
exit 1
fi
;;
*)
echo “Usage: openvpn {start|stop|restart|condrestart|reload|reopen|status}”
exit 1
;;
esac
exit 0