Deeper Look Into OpenVPN

We've written a tutorial before on a simple setup of OpenVPN on a server which allows clients to connect to your server quickly and easily. For the sake of simplicity, that article omitted to mention a a whole lot of other useful settings for OpenVPN. So let's fix that!

Let's look again at our server configuration from last time:

port 1194 proto udp dev tun ca /etc/openvpn/keys/ca.crt cert /etc/openvpn/keys/server.crt key /etc/openvpn/keys/server.key dh /etc/openvpn/keys/dh2048.pem server 172.16.0.0 255.255.255.0 ifconfig-pool-persist ipp.txt keepalive 5 30 comp-lzo persist-key persist-tun status openvpn-status.log 3 verb 3 script-security 3 system max-clients 10

Let's unpack that really quick:

port 1194 designates the listen port, and we can change this port whenever we'd need it. We can also assign different ports to multiple OpenVPN server.

proto udp refers to the network protocol it's using. We could use TCP and UDP but we'll stick with UDP since it allows for better performance.

dev tun this parameter means traffic through the VPN tunnel will be routed. You could also use dev tap here which will designate the connected clients as a bridge between server and client instead.

server 172.16.0.0 255.255.255.0 the server address and the subnet mask. When setting this up, make sure you use only private network ranges: 10.0.0.0/8, 172.16.0.0/12, 192.168.0.0/16.

comp-lzo allows use of algorhythm lzo for data compression.

max-clients 10 limit the maximum connected clients to 10.

status openvpn-status.log 3 creates a log file openvpn-status.log of client information, which will update every 3 seconds.

While these are the parameters we're using for our setup, here are a few more you might find useful:

duplicate-cn this allows multiple clients to connect to your server using the same authentication certificate. This can be useful sometimes.

client-to-client lets connected clients access other clients peer-to-peer. Without this parameter, clients only have access to the server.

crl-verify crl.pem enables checking certificates against a database of revoked certificates. Certificates that have been revoked will be rejected.

client-connect /etc/openvpn/connect.py

client-disconnect /etc/openvpn/disconnect.py designated scripts will run every time a client disconnects. We actually explain this type of script later in this article!

Revoking OpenVPN Certificates

Every sysadmin usually runs into having to check the list of connected clients, release new certificates, revoke old ones, and generally make sure that the server is accessible when it needs to be. We covered generating a new certificate in a past article, so let's go over how to revoke it.

First, we need to run a script '/etc/openvpn/easy-rsa/revoke-full' with the name of the certificate you're trying to revoke. Once done, the file crl.pem will be updated and the revoking will go into effect.

NOTICE: You must have a crl-verify parameter included in your configuration file, as otherwise the certificate will not be included in the database of revoked ones, allowing clients to use it to connect.

Seeing Connected Clients

You can check the list of connected clients inside '/etc/openvpn/openvpn-status.log'. Individual listings will looks something like this:

OpenVPN CLIENT LIST Updated,Mon Jul 11 15:19:21 2016 Common Name,Real Address,Bytes Received,Bytes Sent,Connected Since client15,147.30.234.31:64214,1136171,171517,Mon Jul 11 11:16:40 2016 ROUTING TABLE Virtual Address,Common Name,Real Address,Last Ref 172.18.0.74,client15,147.30.234.31:64214,Mon Jul 11 11:16:46 2016 GLOBAL STATS Max bcast/mcast queue length,76 END

It's going to be difficult to go through entries that look like that, especially in cases where a lot of clients are connected to your server. You can make parsing this information easier by using the grep command, though it'll still be pretty cumbersome to go through.

This is where we get to using scripts. The parameters client-connect and client-disconnect let us use user scrips when clients connect to, or disconnect from, the server. Here's an example of such a script, written in Python:

connect.py:

#!/usr/bin/python # -*- coding: utf-8 -*- import MySQLdb import posix db_server = 'localhost' db_user = 'vpn_db' db_pass = 'your_password' db_base = 'vpn_db' db = MySQLdb.connect(db_server, db_user, db_pass, db_base) with db: c = db.cursor() s = "INSERT IGNORE INTO clients SET name='%s', public_ip='%s', vpn_ip='%s'" % (str(posix.environ['common_name']), str(posix.environ['trusted_ip']), str(posix.environ['ifconfig_pool_remote_ip'])); c.execute (s) db.close()

disconnect.py:

#!/usr/bin/python # -*- coding: utf-8 -*- import MySQLdb import posix db_server = 'localhost' db_user = 'vpn_db' db_pass = 'your_password' db_base = 'vpn_db' db = MySQLdb.connect(db_server, db_user, db_pass, db_base) with db: c = db.cursor() s = "DELETE FROM clients WHERE name='%s' AND busy = '';" % str(posix.environ['common_name']) c.execute (s) db.close()

The first script inserts information on newly connected clients into a 'clients' table inside a 'vpn_db' database, while the second script deletes the entries once the clients disconnect. The table will look something like this:

+---------------------+-----------------+--------------+ | name | public_ip | vpn_ip | +---------------------+-----------------+--------------+ | client15 | 147.30.234.31 | 172.18.0.74 | +---------------------+-----------------+--------------+

With both scripts in place, you will now have a list of currently connected clients that updates in real-time as clients connect and disconnect, as well as lists their private and external IP addresses.

This article is just one example of what you can do, and you can use the code in it or modify it based on your needs.

Monitoring an OpenVPN server usually comes down to checking port 1194's availability and the running 'openvpn' service. Check out our article on Monit setup, for more information on port monitoring.



Hope you learned something from this article, and follow @serversuit for updates on upcoming articles in the future!



Until next time!