OpenConnect VPN aka ocserv is an open-source free VPN solution with enterprise-grade performance and features. It is based on the Cisco AnyConnect VPN protocol which is widely used in the corporate industry. In this tutorial, you will learn how to install the OpenConnect VPN server on a Ubuntu 22.04 machine. You will also learn how to use an OpenConnect client to connect to the server.

Prerequisites

  • A server running Ubuntu 22.04.

  • A non-root user with sudo privileges.

  • A fully qualified domain name (FQDN) like vpn.example.com.

  • Make sure everything is updated.

    $ sudo apt update
    $ sudo apt upgrade
    
  • Few packages that your system needs.

    $ sudo apt install wget curl nano software-properties-common dirmngr apt-transport-https gnupg2 ca-certificates lsb-release ubuntu-keyring unzip -y
    

    Some of these packages may already be installed on your system.

Step 1 – Configure Firewall

The first step is to configure the firewall. Ubuntu comes with ufw (Uncomplicated Firewall) by default.

Check if the firewall is running.

$ sudo ufw status

You should get the following output.

Status: inactive

Allow SSH port so the firewall doesn’t break the current connection on enabling it.

$ sudo ufw allow OpenSSH

Allow HTTP and HTTPS ports as well.

$ sudo ufw allow http
$ sudo ufw allow https

Enable the Firewall

$ sudo ufw enable
Command may disrupt existing ssh connections. Proceed with operation (y|n)? y
Firewall is active and enabled on system startup

Check the status of the firewall again.

$ sudo ufw status

You should see a similar output.

Status: active

To                         Action      From
--                         ------      ----
OpenSSH                    ALLOW       Anywhere
80/tcp                     ALLOW       Anywhere
443                        ALLOW       Anywhere
OpenSSH (v6)               ALLOW       Anywhere (v6)
80/tcp (v6)                ALLOW       Anywhere (v6)
443 (v6)                   ALLOW       Anywhere (v6)

Step 2 – Install Git

Step 3 – Install OpenConnect

Ubuntu 22.04 ships with an older version (1.1.3) of OpenConnect. If you are satisfied with that, you can install it using the following command.

$ sudo apt install ocserv

However, for this tutorial, we will install the latest version (1.1.6) of OpenConnect. For this, we will need to build it from the source.

Install the dependencies required for building the source.

$ sudo apt install -y libgnutls28-dev libev-dev libpam0g-dev liblz4-dev libseccomp-dev 
	libreadline-dev libnl-route-3-dev libkrb5-dev libradcli-dev 
	libcurl4-gnutls-dev libcjose-dev libjansson-dev libprotobuf-c-dev 
	libtalloc-dev libhttp-parser-dev protobuf-c-compiler gperf 
	nuttcp lcov libuid-wrapper libpam-wrapper libnss-wrapper 
	libsocket-wrapper gss-ntlmssp haproxy iputils-ping freeradius 
	gawk gnutls-bin iproute2 yajl-tools tcpdump autoconf automake

Clone the ocserv Git repository.

$ git clone https://gitlab.com/openconnect/ocserv.git

Switch to the cloned directory.

$ cd ocserv

Generate configuration scripts.

$ autoreconf -fvi

Compile the source code. Ignore any deprecated warnings.

$ ./configure && make

Install ocserv.

$ sudo make install

The files will be installed to the /usr/local/bin and /usr/local/sbin directories. Copy the systemd service file.

$ sudo cp doc/systemd/standalone/ocserv.service /etc/systemd/system/ocserv.service

Open the service file for editing.

$ sudo nano /etc/systemd/system/ocserv.service

Change the path to the ocserv binary in the following line

$ ExecStart=/usr/sbin/ocserv --foreground --pid-file /run/ocserv.pid --config /etc/ocserv/ocserv.conf

to the following.

$ ExecStart=/usr/local/sbin/ocserv --foreground --pid-file /run/ocserv.pid --config /etc/ocserv/ocserv.conf

Save the file by pressing Ctrl X and entering Y when prompted.

Reload the system daemon.

$ sudo systemctl daemon-reload

Step 4 – Generate SSL Certificates

We need to install Certbot to generate the SSL certificate. You can either install Certbot using Ubuntu’s repository or grab the latest version using the Snapd tool. We will be using the Snapd version.

Ubuntu 22.04 comes with Snapd installed by default. Run the following commands to ensure that your version of Snapd is up to date.

$ sudo snap install core && sudo snap refresh core

Install Certbot.

$ sudo snap install --classic certbot

Use the following command to ensure that the Certbot command can be run by creating a symbolic link to the /usr/bin directory.

$ sudo ln -s /snap/bin/certbot /usr/bin/certbot

There are two possibilities when it comes to generating an SSL certificate. If you don’t have a web server running on your system, you can use the standalone method to generate the certificate. Run the following command to create the certificate using the standalone plugin for Certbot.

$ sudo certbot certonly --standalone --agree-tos --no-eff-email --staple-ocsp --preferred-challenges http -m [email protected] -d vpn.example.com

The above command will download a certificate to the /etc/letsencrypt/live/vpn.example.com directory on your server.

Next, if you have a server running on your system, you can either use the webroot plugin or the Nginx or Apache plugins if you are using them. For Nginx or Apache servers, you can simply run the command below.

$ sudo certbot certonly --nginx --agree-tos --no-eff-email --staple-ocsp --preferred-challenges http -m [email protected] -d vpn.example.com

or

$ sudo certbot certonly --apache --agree-tos --no-eff-email --staple-ocsp --preferred-challenges http -m [email protected] -d vpn.example.com

If you have a different server, then we will need to use the webroot plugin. For that, create the web root directory.

$ sudo mkdir -p /var/www/ocserv

Set the server as the owner of the web root directory. In our case, we are using www-data as the server user.

$ sudo chown www-data:www-data /var/www/ocserv -R

Next, configure your server to serve the domain vpn.example.com at the /var/www/ocserv directory. Restart the server. Next, generate the certificate using the following command.

$ sudo certbot certonly --webroot --agree-tos --no-eff-email --staple-ocsp --preferred-challenges http -m [email protected] -d vpn.example.com

Check the Certbot renewal scheduler service.

$ sudo systemctl list-timers

You will find snap.certbot.renew.service as one of the services scheduled to run.

NEXT                        LEFT          LAST                        PASSED        UNIT                       ACTIVATES
Wed 2023-04-19 10:31:47 UTC 2h 55min left Wed 2023-04-19 03:31:58 UTC 4h 3min ago   ua-timer.timer             ua-timer.service
Wed 2023-04-19 12:02:42 UTC 4h 26min left Wed 2023-04-19 03:19:20 UTC 4h 16min ago  motd-news.timer            motd-news.service
Wed 2023-04-19 18:19:56 UTC 10h left      Wed 2023-04-19 07:19:52 UTC 16min ago     apt-daily.timer            apt-daily.service
Wed 2023-04-19 22:51:00 UTC 15h left      n/a                         n/a           snap.certbot.renew.timer   snap.certbot.renew.service

Do a dry run of the process to check whether the SSL renewal is working fine.

$ sudo certbot renew --dry-run

If you see no errors, you are all set. Your certificate will renew automatically.

Step 5 – Configure OpenConnect

If you are installed ocserv using APT, then the configuration file should already be available at the /etc/ocserv/ocserv.conf location. But if you built the package from the source, we need to copy the configuration file.

Create the directory for the configuration file.

$ sudo mkdir /etc/ocserv

Copy the configuration file.

$ sudo cp /home/username/ocserv/doc/sample.config /etc/ocserv/ocserv.conf

Open the file for editing.

$ sudo nano /etc/ocserv/ocserv.conf

Change the auth parameter value to the following. This will allow users to use separate VPN accounts.

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

By default, OpenConnect uses the 443 TCP and UDP ports. We will be using only the TCP port for connection, therefore, disable the UDP port by commenting it out.

tcp-port = 443
#udp-port = 443

If you have a web server running on port 443, then change the value of the TCP port by changing the value.

tcp-port = 8443

Next, find the variables server-crt and server-key and change their values as follows.

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

Set the maximum number of clients allowed. The default value is 16. Set as 0 for unlimited.

max-clients = 16

Set the number of devices a user can use at the same time. The default value is 2. Set as 0 for unlimited.

max-same-clients = 2

By default, OpenConnect sends keepalive packets every 9 hours (32400 seconds). This is too high of a value. Set it to 60 seconds to reduce the chance of VPN connection dropout.

keepalive = 60

Change the value of the try-mtu-discovery to true to enable MTU discovery. It can optimize VPN performance.

try-mtu-discovery = true

Configure the time that a client is allowed to stay idle before being disconnected by uncommenting the following variables. If you want the client to stay connected indefinitely, leave them as it is.

idle-timeout=1200
mobile-idle-timeout=1800

Set the default domain name for the OpenConnect VPN.

default-domain = vpn.example.com

Change the default IPv4 configuration to avoid IP address collision. We will use 10.10.10.0 as the value.

ipv4-network = 10.10.10.0

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

tunnel-all-dns = true

Change the DNS resolver to Google DNS. Add the second entry as well.

dns = 8.8.8.8
dns = 8.8.4.4

Comment out all the route parameters by adding the hash (#) symbol in front of it.

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

# Subsets of the routes above that will not be routed by
# the server.

#no-route = 192.168.5.0/255.255.255.0

Save the file by pressing Ctrl X and entering Y when prompted.

Step 6 – Start OpenConnect Server

Start the OpenConnect VPN server.

$ sudo systemctl start ocserv

Check the status of the service.

$ sudo systemctl status ocserv

You will get a similar output.

? ocserv.service - OpenConnect SSL VPN server
     Loaded: loaded (/etc/systemd/system/ocserv.service; disabled; vendor preset: enabled)
     Active: active (running) since Thu 2023-04-20 08:52:18 UTC; 2s ago
       Docs: man:ocserv(8)
   Main PID: 19965 (ocserv-main)
      Tasks: 2 (limit: 1026)
     Memory: 1.4M
        CPU: 9ms
     CGroup: /system.slice/ocserv.service
             ??19965 ocserv-main  
             ??19966 ocserv-sm 

Apr 20 08:52:18 openconnect ocserv[19965]: note: skipping 'pid-file' config option
Apr 20 08:52:18 openconnect ocserv[19965]: note: vhost:default: setting 'plain' as primary authentication method
Apr 20 08:52:18 openconnect ocserv[19965]: error connecting to sec-mod socket '/var/run/ocserv-socket.a4413bc9': No such file or directory
Apr 20 08:52:18 openconnect ocserv[19965]: note: setting 'file' as supplemental config option
Apr 20 08:52:18 openconnect ocserv[19965]: listening (TCP) on 0.0.0.0:443...
Apr 20 08:52:18 openconnect ocserv[19965]: listening (TCP) on [::]:443...
Apr 20 08:52:18 openconnect ocserv[19966]: ocserv[19966]: sec-mod: reading supplemental config from files
Apr 20 08:52:18 openconnect ocserv[19966]: sec-mod: reading supplemental config from files
Apr 20 08:52:18 openconnect ocserv[19966]: ocserv[19966]: sec-mod: sec-mod initialized (socket: /var/run/ocserv-socket.a4413bc9.0)
Apr 20 08:52:18 openconnect ocserv[19966]: sec-mod: sec-mod initialized (socket: /var/run/ocserv-socket.a4413bc9.0)

If you see the error regarding connecting to sec-mod socket, ignore it. It’s normal. It will initialize the file if it doesn’t find it.

Step 7 – Create VPN accounts

You can create VPN accounts using the ocpasswd utility. Run the following command to create a new VPN account.

$ sudo ocpasswd -c /etc/ocserv/ocpasswd username
Enter password:
Re-enter password:

The password will be saved to the /etc/ocserv/ocpasswd file. To reset the password for the username, run the above command again. Run the above command with a different user to create another account.

Step 8 – Enable IP Forwarding

For the VPN server to route packets between the client and the Internet, you need to enable IP forwarding by running the following command.

$ echo "net.ipv4.ip_forward = 1" | sudo tee /etc/sysctl.d/60-custom.conf

Run the following commands to enable the TCP BBR algorithm to boost TCP speed.

$ echo "net.core.default_qdisc=fq" | sudo tee -a /etc/sysctl.d/60-custom.conf
$ echo "net.ipv4.tcp_congestion_control=bbr" | sudo tee -a /etc/sysctl.d/60-custom.conf

Make the changes permanent using the following command.

$ sudo sysctl -p /etc/sysctl.d/60-custom.conf

Step 9 – Configure IP Masquerading

The next step is to set up IP masquerading in the firewall so that the VPN server can work as a virtual router for the clients. Find the name of the server’s main network interface.

$ ip addr

You will get a similar output.

1: lo:  mtu 65536 qdisc noqueue state UNKNOWN group default qlen 1000
    link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
    inet 127.0.0.1/8 scope host lo
       valid_lft forever preferred_lft forever
    inet6 ::1/128 scope host
       valid_lft forever preferred_lft forever
2: enp1s0:  mtu 1500 qdisc fq state UP group default qlen 1000
    link/ether 56:00:04:67:7e:79 brd ff:ff:ff:ff:ff:ff
    inet 95.179.138.135/23 metric 100 brd 95.179.139.255 scope global dynamic enp1s0
       valid_lft 66999sec preferred_lft 66999sec
    inet6 2a05:f480:1400:2381:5400:4ff:fe67:7e79/64 scope global dynamic mngtmpaddr noprefixroute
       valid_lft 2591657sec preferred_lft 604457sec
    inet6 fe80::5400:4ff:fe67:7e79/64 scope link
       valid_lft forever preferred_lft forever

In our case, enp1s0 is the name of the interface. Add the iptables command in a UFW configuration file by opening it for editing.

$ sudo nano /etc/ufw/before.rules

Add the following lines at the end of the file. Replace enp1s0 in the code with your network interface.

# NAT table rules
*nat
:POSTROUTING ACCEPT [0:0]
-A POSTROUTING -s 10.10.10.0/24 -o enp1s0 -j MASQUERADE

# End each table with the 'COMMIT' line or these rules won't be processed
COMMIT

Find the following lines in the file.

# ok icmp code for FORWARD
-A ufw-before-forward -p icmp --icmp-type destination-unreachable -j ACCEPT
-A ufw-before-forward -p icmp --icmp-type time-exceeded -j ACCEPT
-A ufw-before-forward -p icmp --icmp-type parameter-problem -j ACCEPT
-A ufw-before-forward -p icmp --icmp-type echo-request -j ACCEPT

Paste the following lines after it.

# allow forwarding for trusted network
-A ufw-before-forward -s 10.10.10.0/24 -j ACCEPT
-A ufw-before-forward -d 10.10.10.0/24 -j ACCEPT

<img alt="IP Masquerading Code in UFW" data-ezsrc="https://kirelos.com/wp-content/uploads/2023/05/echo/nMs8M1X.png" ezimgfmt="rs rscb5 src ng ngcb5" height="154" referrerpolicy="no-referrer" src="data:image/svg xml,” width=”611″>

Save the file by pressing Ctrl X and entering Y when prompted.

Restart the firewall.

$ sudo systemctl restart ufw

You can check the Masquerade rule using the following command.

$ sudo iptables -t nat -L POSTROUTING

You will get the following output.

Chain POSTROUTING (policy ACCEPT)
target     prot opt source               destination
MASQUERADE  all  --  10.10.10.0/24        anywhere

Step 10 – Connect using OpenConnect Client

We will install OpenConnect Client on a Ubuntu 22.04 machine. Run the following command to install the client.

$ sudo apt install openconnect

Next, connect to the VPN server using the following command. The -b flag makes the client run in the background once the connection is established.

$ sudo openconnect -b vpn.example.com:443

You will be asked to enter the VPN username and password. Enter the credentials created in step 7.

POST https://vpn.example.com/
Connected to 95.179.138.135:443
SSL negotiation with vpn.example.com
Connected to HTTPS on vpn.example.com with ciphersuite (TLS1.3)-(ECDHE-SECP256R1)-(ECDSA-SECP256R1-SHA256)-(AES-256-GCM)
XML POST enabled
Please enter your username.
Username:navjot
POST https://vpn.example.com/auth
Please enter your password.
Password:
POST https://vpn.example.com/auth

You will see the following output on a successful connection. DTLS is disabled because we disabled the UDP.

Got CONNECT response: HTTP/1.1 200 CONNECTED
CSTP connected. DPD 90, Keepalive 60
No DTLS address
Set up UDP failed; using SSL instead
Configured as 192.168.1.13, with SSL connected and DTLS disabled
Continuing in background; pid 1650

Run the following command to stop the connection.

$ sudo pkill openconnect

Let us create some systemd scripts for OpenConnect. The first script is to get the client to auto-connect on system startup.

Create and open the service file for editing.

$ sudo nano /etc/systemd/system/openconnect.service

Paste the following code in it.

[Unit]
  Description=OpenConnect VPN Client
  After=network-online.target systemd-resolved.service
  Wants=network-online.target

[Service]
  Type=simple
  ExecStart=/bin/bash -c '/bin/echo -n password | /usr/sbin/openconnect vpn.example.com -u username --passwd-on-stdin'
  KillSignal=SIGINT
  Restart=always
  RestartSec=2

[Install]
  WantedBy=multi-user.target

Save the file by pressing Ctrl X and entering Y when prompted.

Enable the service.

$ sudo systemctl enable openconnect.service

Start the service.

$ sudo systemctl start openconnect.service

To restart your VPN connection automatically when your PC resumes from the suspend state, you need to create another systemd script.

Create and open the restart script for editing.

$ sudo nano /etc/systemd/system/openconnect-restart.service

Paste the following code in it.

[Unit]
Description=Restart OpenConnect client when resuming from suspend
After=suspend.target

[Service]
Type=simple
ExecStart=/bin/systemctl --no-block restart openconnect.service

[Install]
WantedBy=suspend.target

Save the file by pressing Ctrl X and entering Y when prompted.

Enable the service.

$ sudo systemctl enable openconnect-restart.service

We can also create a service to restart the VPN connection automatically when it drops. Create and open the VPN check service for editing.

$ sudo nano /etc/systemd/system/openconnect-check.service

Paste the following code in it.

[Unit]
Description=OpenConnect VPN Connectivity Checker
After=openconnect.service

[Service]
Type=simple
ExecStart=/bin/bash -c 'for ((; ; )) do (ping -c9 10.10.10.1 || systemctl restart openconnect) done'

[Install]
WantedBy=multi-user.target

Save the file by pressing Ctrl X and entering Y when prompted.

Enable and start the service.

$ sudo systemctl enable enable openconnect-check.service --now

This will run the ping command forever to check the VPN connection. If it drops, it will automatically restart OpenConnect.

You can download OpenConnect GUI Clients if you want. However, they haven’t been updated in quite a while. If you want an updated GUI client, you can visit the OpenConnect GUI GitLab repository and compile it yourself.

Conclusion

That completes our tutorial on installing an OpenConnect VPN server on a Ubuntu 22.04 server and using the command line client to connect to it. If you have any questions, post them in the comments below.