Blog about software development


Install OpenConnect VPN server on KVM

07 Feb 2020 - by 'Maurits van der Schee'

In a previous post I have shown how to add an IPsec IKEv2 VPN to your (Ubuntu 18.04) KVM setup. In this post I will show you how to add and configure OpenConnect VPN. I will show how to install the VPN endpoint on a virtual machine, as a replacement for the VPN installation that we did in the previous post. OpenConnect may be easier to setup and maintain, but it is not clientless on Windows 10 and does require a (user-friendly and free) VPN client.

Install OpenConnect (ocserv)

First you need to install the OpenConnect VPN software (on Ubuntu 18.04):

sudo apt install ocserv

The config file for this software is "/etc/ocserv.conf".

Configure forwarding on the gateway

In this tutorial I assume that you are running the VPN server as a guest on your KVM host machine and that the KVM host machine is running UFW.

Add the following to "/etc/ufw/before.rules" in the "nat" chain (as explained in the pevious post) on the KVM host:

-A PREROUTING -i eno1 -p tcp -d --dport 8443 -j DNAT --to-destination
-A PREROUTING -i eno1 -p udp -d --dport 8443 -j DNAT --to-destination

Note that in this example "" is the public IP address of the KVM host and "" is the (private and only) IP address of the VPN server.

Forward port 80 on the webserver

If you run a webserver you have probably forwarded port 80 to this webserver. Since we want to use "certbot" we need to configure a proxy forward for the specific hostame of your VPN server. We use "mod_proxy_http" for this.

sudo a2enmod proxy_http

Then add the following in "/etc/apache2/sites-available/100-vpncertbot.conf"

<VirtualHost *:80>
    ServerName vpn.tqdev.com
    # Proxy all requests
    ProxyPreserveHost On
    ProxyPass /

Replace "" with the internal IP address of your VPN server and "vpn.tqdev.com" with the hostname you use for your VPN server.

Configure Lets Encrypt automatic certificate renewal

To install the latest "certbot" you may run:

sudo add-apt-repository ppa:certbot/certbot
sudo apt update
sudo apt install certbot
sudo certbot certonly --standalone --preferred-challenges http -d vpn.tqdev.com
sudo nano /etc/letsencrypt/renewal/vpn.tqdev.com.conf

A text file will open with some configuration options. Add your hook on the last line:

renew_hook = systemctl restart ocserv.service

Save and close the file, then run a "certbot dry run" to make sure the syntax is ok:

sudo certbot renew --dry-run

This command should give a warning:

Dry run: skipping deploy hook command

And otherwise run correct, printing:

Congratulations, all renewals succeeded.

Showing that certbot configuration is correct.

OpenConnect configuration

We configure OpenConnect by editing the file "/etc/ocserv.conf" so that it has the following content:

auth = "plain[/etc/ocserv/ocpasswd]"
tcp-port = 8443
udp-port = 8443
run-as-user = nobody
run-as-group = daemon
socket-file = /var/run/ocserv-socket
server-cert = /etc/letsencrypt/live/vpn.tqdev.com/fullchain.pem
server-key = /etc/letsencrypt/live/vpn.tqdev.com/privkey.pem
ca-cert = /etc/letsencrypt/live/vpn.tqdev.com/chain.pem
use-occtl = true
max-clients = 25
max-same-clients = 1
device = vpns
dns =
# client addresses:
ipv4-network =
default-domain = kvm
route =

Make sure the "leftid" matches your hostname prefixed with an "at" sign (which means: don't resolve). Adjust the "leftsubnet" to match with your private network and the "rightsourceip" with the (virtual) ip addresses you want to give to clients connecting to your VPN server.

If you want to capture all traffic and set the default route over the VPN tunnel, you need to set:

route = default

Using the command "ocpasswd" you can add users to the file "/etc/ocserv/ocpasswd":

sudo ocpasswd -c /etc/ocserv/ocpasswd username1

The password is not stored in plain text. If you want to know who is connected, run:

sudo occtl show users

Use "occtl help" for other management features.

Add DNS support for guests

You probably noted the "default-domain = kvm" line in the config. It allows VPN clients (and virtual machines) to contact each other by name. This configuration is called "split-DNS". In order to add it you must edit the network configuration using:

virsh net-edit default

Look for the line:

<ip address='' netmask=''>

Add a domain configuration on the line before it, like this:

<domain name='kvm' localOnly='yes'/>
<ip address='' netmask=''>

Now this setting allows the named virtual machine "maurits-cloud" to be reached by other virtual machines on the hostname "maurits-cloud.kvm".

This will NOT be effective until you destroy and start the network.

Set up IP forwarding

Add the following lines to the end of the file "/etc/sysctl.conf" to make your Linux machine act as an IPv4 router:

# enable ipv4 routing
net.ipv4.ip_forward = 1
net.ipv4.conf.all.proxy_arp = 1

Note that the "proxy_arp" is an alternative for masquerading all traffic on the VPN host. Now you need to run:

sudo sysctl -p

This command reloads sysctl config file and makes the settings effective.

Fixing DTLS Handshake Failure

Although connecting might succeed, it may connect slow and you may encounter the following message in the (sys)log:

DTLS handshake failed: Resource temporarily unavailable, try again.

To fix this error, we need to edit the "/lib/systemd/system/ocserv.service" file. First copy it from the "/lib/systemd/system/" directory to "/etc/systemd/system/" directory. This avoids your modifications from being overridden or reverted by a package update.

sudo cp /lib/systemd/system/ocserv.service /etc/systemd/system/ocserv.service
sudo nano /etc/systemd/system/ocserv.service

Comment out the following two lines:




Save and close the file. Then reload systemd and restart ocserv service.

sudo systemctl daemon-reload
sudo systemctl stop ocserv.socket
sudo systemctl disable ocserv.socket
sudo systemctl restart ocserv.service

The ocserv systemd service won’t output any message if it fails to restart, so we need to check the status to make sure it’s actually running.

systemctl status ocserv

It should show "active (running)".

Installing the client on Ubuntu

If you are connecting from Windows 10, then you need to install external client software for this VPN connection.

If you use Ubuntu, then you also need to install a client. You can do so by running:

sudo apt install network-manager-openconnect-gnome

If you don't see the VPN option marked "openconnect" in the network manager applet, then you may have to log out and in for it to appear.

Next: Installing IKEv1 L2TP VPN

In the next post I will show you how to add an IKEv1 L2TP to your KVM setup. I will show how to install the VPN endpoint on a virtual machine, as a replacement for the VPN installation that we did in this (and previous) post. IKEv1 L2TP may be easier to configure than IKEv2 and also does not require a VPN client on Windows 10.

PS: Liked this article? Please share it on Facebook, Twitter or LinkedIn.