How to Set up OpenConnect VPN Server (ocserv) on Ubuntu 16.04/17.10 with Let’s Encrypt

This tutorial is going to show you how to install OpenConnect VPN server on Ubuntu 16.04/17.10. OpenConnect VPN server, aka ocserv, is an open-source implementation of Cisco AnyConnnect VPN protocol, which is popular among businesses and universities. AnyConnect is a SSL-based VPN protocol that allows individual users to connect to a remote network.

Features of OpenConnect VPN server:

  • Lightweight and fast. In my test, I can watch YouTube in 4k with OpenConnect VPN. YouTube is blocked in my country.
  • Compatible with Cisco AnyConnect client
  • Supports password authentication and certificate authentication
  • Easy to set up

The gnutls-bin software package provides tools to create your own CA and server certificate, but we will obtain and install Let’s Encrypt certificate. The advantage of using Let’s Encrypt certificate is that it’s free, easier to set up and trusted by VPN client software.

Installing OpenConnect VPN Server on Ubuntu 16.04/17.10

Log into your Ubuntu 16.04/17.10 server. Then use apt to install the ocserv package,which is included in Ubuntu repository since 16.04.

sudo apt install ocserv

Once installed, the OpenConnect VPN server is automatically started. You can check its status with:

systemctl status ocserv

Sample output:

 ocserv.service - OpenConnect SSL VPN server
   Loaded: loaded (/lib/systemd/system/ocserv.service; enabled; vendor preset: enabled
   Active: active (running) since Thu 2017-11-30 05:45:07 UTC; 11s ago
     Docs: man:ocserv(8)
 Main PID: 19235 (ocserv-main)
   CGroup: /system.slice/ocserv.service
           ├─19235 ocserv-main                                                  
           └─19242 ocserv-secm 

If it’s not running, then you can start it with:

sudo systemctl start ocserv

By default OpenConnect VPN server listens on TCP and UDP port 443. If it’s being used by web server, then the VPN server can’t be started. We will see how to change the port in OpenConnect VPN configuration file later.

Installing Let’s Encrypt Client (Certbot) on Ubuntu 16.04/17.10 Server

Run the following commands to install the latest version of certbot from the official PPA. software-properties-common is required if you want to install packages from PPA. It may be missing on your Ubuntu server.

sudo apt install software-properties-common

sudo add-apt-repository ppa:certbot/certbot

sudo apt update

sudo apt install certbot

To check version number, run

certbot --version

Sample output:

certbot 0.19.0

Obtaining a TLS Certificate from Let’s Encrypt

Standalone Plugin

If there’s no web server running on your Ubuntu 16.04/17.10 server and you want OpenConnect VPN server to use port 443, then you can use the standalone plugin to obtain TLS certificate from Let’s Encrypt. Run the following command. Don’t forget to set A record for your domain name.

sudo certbot certonly --standalone --preferred-challenges http --agree-tos --email your-email-address -d vpn.example.com

Explanation:

  • certonly: Obtain a certificate but don’t install it.
  • --standalone: Use the standalone plugin to obtain a certificate
  • --preferred-challenges http: Perform http-01 challenge to validate our domain, which will use port 80. By default the standalone plugin will perform tls-sni challenge, which uses port 443. Since port 443 is already used by OpenConnect VPN server, we need to change the default behavior.
  • --agree-tos: Agree to Let’s Encrypt terms of service.
  • --email: Email address is used for account registration and recovery.
  • -d: Specify your domain name.

As you can see the from the following screenshot, I successfully obtained the certificate.

install openconnect ubuntu server

Using webroot Plugin

If your Ubuntu 16.04/17.10 server has a web server listening on port 80 and 443, and you want OpenConnect VPN server to use a different port, then it’s a good idea to use the webroot plugin to obtain a certificate because the webroot plugin works with pretty much every web server and we don’t need to install the certificate in the web server.

First, you need to create a virtual host for vpn.example.com.

Apache

If you are using Apache, then

sudo nano /etc/apache2/sites-available/vpn.example.com.conf

And paste the following lines into the file.

<VirtualHost *:80>        
        ServerName vpn.example.com

        DocumentRoot /var/www/vpn.example.com
</VirtualHost>

Save and close the file. Then create the web root directory.

sudo mkdir /var/www/vpn.example.com

Set www-data (Apache user) as the owner of the web root.

sudo chown www-data:www-data /var/www/vpn.example.com -R

Enable this virtual host.

sudo a2ensite vpn.example.com

Reload Apache for the changes to take effect.

sudo systemctl reload apache

Once virtual host is created and enabled, run the following command to obtain Let’s Encrypt certificate using webroot plugin.

sudo certbot certonly --webroot --agree-tos --email your-email-address -d vpn.example.com -w /var/www/vpn.example.com

Nginx

If you are using Nginx, then

sudo nano /etc/nginx/conf.d/vpn.example.com.conf

Paste the following lines into the file.

server {
      listen 80;
      server_name vpn.example.com;

      root /var/www/vpn.example.com/;

      location ~ /.well-known/acme-challenge {
         allow all;
      }
}

Save and close the file. Then create the web root directory.

sudo mkdir /var/www/vpn.example.com

Set www-data (Nginx user) as the owner of the web root.

sudo chown www-data:www-data /var/www/vpn.example.com -R

Reload Nginx for the changes to take effect.

sudo systemctl reload nginx

Once virtual host is created and enabled, run the following command to obtain Let’s Encrypt certificate using webroot plugin.

sudo certbot certonly --webroot --agree-tos --email your-email-address -d vpn.example.com -w /var/www/vpn.example.com

Editing OpenConnect VPN Server Configuration File

Edit ocserv configuration file.

sudo nano /etc/ocserv/ocserv.conf

First, configure password authentication. By default, password authentication through PAM (Pluggable Authentication Modules) is enabled, which allows you to use Ubuntu system accounts to login from VPN clients. This behavior can be disabled by commenting out the following line.

auth = "pam[gid-min=1000]"

If we want users to use separate VPN accounts instead of system accounts to login, we need to add the following line to the file to enable password authentication with a plain password file.

auth = "plain[passwd=/etc/ocserv/ocpasswd]"

After finishing editing this config file, we will see how to use ocpasswd tool to generate the /etc/ocserv/ocpasswd file, which contains a list of usernames and encoded passwords.

Note: Ocserv supports client certificate authentication, but since we’re using Let’s Encrypt, which does not issue client certificate, we can’t use certificate authentication.

Next, if you don’t want ocserv to use TCP and UDP port 443, then find the following two lines and change the port number. Otherwise leave them alone.

tcp-port = 443
udp-port = 443

Then find the following two lines. We need to changes them.

server-cert = /etc/ssl/certs/ssl-cert-snakeoil.pem
server-key = /etc/ssl/private/ssl-cert-snakeoil.key

Replace the default setting with the path of Let’s Encrypt server certificate and server key file.

server-cert = /etc/letsencrypt/live/vpn.example.com/fullchain.pem
server-key = /etc/letsencrypt/live/vpn.example.com/privkey.pem

Then, set the maximal number of clients. Default is 16. Set to zero for unlimited.

max-clients = 16

Set the number of devices a user is able to login from at the same time. Default is 2. Set to zero for unlimited.

max-same-clients = 2

Next, find the following line. Change false to true to enable MTU discovery.

try-mtu-discovery = false

After that, set the default domain to vpn.example.com.

default-domain = vpn.example.com

Uncomment the following line to tunnel all DNS queries via the VPN.

tunnel-all-dns = true

Change DNS server address

dns = 8.8.8.8

Then comment out all the route directives (add # symbol at the beginning of the following four lines), which will set the server as the default gateway for the clients.

route = 10.10.10.0/255.255.255.0
route = 192.168.0.0/255.255.0.0
route = fef4:db8:1000:1001::/64

no-route = 192.168.5.0/255.255.255.0

Save and close the file  Then restart the VPN server for the changes to take effect.

sudo systemctl restart ocserv

Fixing DTLS Handshake Failure

On Ubuntu 16.04 and Ubuntu 17.10, ocserv daemon ocserv.socket does not respect “listen-host” value from configuration file, which will cause the following error when clients connect to VPN server.

DTLS handshake failed: Resource temporarily unavailable, try again.

To fix this error, we need to edit the ocserv.service file. We first copy the original file in /lib/systemd/system/ directory to /etc/systemd/system/ directory, then edit it, because we don’t want new version of ocserv package to override our modifications. (To learn more about systemd unit files, run man systemd.unit.)

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.

Requires=ocserv.socket

Also=ocserv.socket

Save and close the file. Then reload systemd

sudo systemctl daemon-reload

Stop ocserv.socket and disable it.

sudo systemctl stop ocserv.socket

sudo systemctl disable ocserv.socket

Restart ocserv service.

sudo systemctl restart ocserv.service

Creating VPN Accounts

Now use the ocpasswd tool to generate VPN accounts.

sudo ocpasswd -c /etc/ocserv/ocpasswd username

You will be asked to set a password for the user and the information will be saved to /etc/ocserv/ocpasswd file.

Enable IP Forwarding

In order for the VPN server to route packets between VPN client and the outside world, we need to enable IP forwarding. Edit sysctl.conf file.

sudo nano /etc/sysctl.conf

Add the following line the the end of this file.

net.ipv4.ip_forward = 1

Save and close the file. Then apply the changes with the below command. The -p option will load sysctl settings from /etc/sysctl.conf file. This command will preserve our changes across system reboots.

sudo sysctl -p

Configure Firewall for IP Masquerading

Find the name of your server’s main network interface.

ip addr

As you can see, it’s named ens3 on my Ubuntu server.

openconnect ubuntu command line

Then run the following command to configure IP masquerading. Replace ens3 with your own network interface name.

sudo iptables -t nat -A POSTROUTING -o ens3 -j MASQUERADE

The above command append (-A) a rule to the end of of POSTROUTING chain of nat table. It will link your virtual private network with the Internet. And also hide your network from the outside world. So the Internet can only see your VPN server’s IP, but can’t see your VPN client’s IP, just like your home router hides your private home network.

Open Port 443 in Firewall

Run the following command to open TCP and UDP port 443. If you configured a different port for ocserv, then open your preferred port.

sudo iptables -I INPUT -p tcp --dport 443 -j ACCEPT

sudo iptables -I INPUT -p udp --dport 443 -j ACCEPT

Preserving Iptables Rules

By default, iptables ruls are lost after reboot. To preserve them, you can switch to root user and then save your rules to a file.

su -

iptables-save > /etc/iptables.rules

Then create a systemd service file.

nano /etc/systemd/system/iptables-restore.service

Put the following lines into the file.

[Unit]
Description=Packet Filtering Framework
Before=network-pre.target
Wants=network-pre.target

[Service]
Type=oneshot
ExecStart=/sbin/iptables-restore /etc/iptables.rules
ExecReload=/sbin/iptables-restore /etc/iptables.rules
RemainAfterExit=yes

[Install]
WantedBy=multi-user.target

Save and close the file. Then reload systemd daemon and enable iptables-restore service.

sudo systemctl daemon-reload

sudo systemctl enable iptables-restore

Remember to save iptables rules to the file after making changes.

How to Install and Use OpenConnect VPN client on Ubuntu 16.04/17.10 Desktop

Run the following command to install OpenConnect VPN command line client on Ubuntu desktop.

sudo apt install openconnect

You can Connect to VPN from the command line like below. -b flag will make it run in the background after connection is established.

sudo openconnect -b vpn.example.com:port-number

You will be asked to enter VPN username and password. If connection is successfully established, you will see the following message.

Got CONNECT response: HTTP/1.1 200 CONNECTED
CSTP connected. DPD 90, Keepalive 32400
Connected tun0 as 192.168.1.139, using SSL
Established DTLS connection (using GnuTLS). Ciphersuite (DTLS1.2)-(RSA)-(AES-256-GCM).

To stop the connection, run:

sudo pkill openconnect

To run the client non-interactively, use the following syntax.

echo -n password | sudo openconnect -b vpn.example.com -u username --passwd-on-stdin

If you want to use Network Manager to manage VPN connection, then you also need to install these packages.

sudo apt install network-manager-openconnect network-manager-openconnect-gnome

Auto-Connect on System Startup

First, create a systemd service file for /etc/rc.local script file.

sudo nano /etc/systemd/system/rc-local.service

Put the following lines to the file.

[Unit]
 Description=/etc/rc.local Compatibility
 ConditionPathExists=/etc/rc.local

[Service]
 Type=forking
 ExecStart=/etc/rc.local start
 TimeoutSec=0
 StandardOutput=tty
 RemainAfterExit=yes
 SysVStartPriority=99

[Install]
 WantedBy=multi-user.target

Save and close the file. Then edit /etc/rc.local file.

sudo nano /etc/rc.local

The contents should be like the following.

#!/bin/sh -e

echo -n password | sudo openconnect -b vpn.example.com -u username --passwd-on-stdin

exit 0

Save and close the file. Make sure it’s executable.

sudo chmod +x /etc/rc.local

Reload systemd daemon and enable rc-local.service.

sudo systemctl daemon-reload

sudo systemctl enable rc-local.service

Speed

OpenConnect VPN is pretty fast. I can use it to watch 4k videos on YouTube.

ocserv letsencrypt

Auto-Renew Let’s Encrypt Certificate

Edit root user’s crontab file.

sudo crontab -e

Add the following line at the end of the file. It’s necessary to restart ocserv service for the VPN server to pick up new certificate and key file.

@daily certbot renew --quiet && systemctl restart ocserv

Troubleshooting

Note that if you are using OpenVZ VPS, make sure you enable the TUN virtual networking device in VPS control panel.

If you encounter any problem, then check OpenConnect VPN server log.

sudo journalctl -xe -u ocserv.service

I found that if I change port 443 to a different port, the Internet filtering system of my country will block this VPN connection.

That’s it! I hope this tutorial helped you install and configure OpenConnect VPN on Ubuntu 16.04 and Ubuntu 17.10. As always, if you found this post useful, then subscribe to our free newsletter.

Rate this tutorial
[Total: 4 Average: 5]