Tech 6 min read

OpenConnect (ocserv) server setup notes

IkesanContents

ShadowSocks, V2Ray, SoftEther, and WireGuard all already had notes, so I put OpenConnect here as well.

What OpenConnect is

OpenConnect is an open-source compatible implementation of Cisco AnyConnect SSL VPN. It lets you use the same AnyConnect client that is commonly used in enterprise VPNs.

Compared with other protocols:

  • SSL/TLS-based: it looks like HTTPS traffic, so it is harder to block
  • DTLS support: high-speed UDP transport is available
  • Enterprise-oriented: compatible with Cisco AnyConnect clients

It is often confused with IKEv2, but IKEv2 is IPsec-based and is easier for GFW-style filtering to detect. OpenConnect is SSL/TLS-based, so it is a different beast.

Server setup

These steps are for CentOS 7.

Install

sudo yum install -y ocserv

Prepare certificates

If you use Let’s Encrypt as recommended, place the issued certificates like this:

cd /etc/ocserv
sudo vi /etc/ocserv/server-cert.pem  # contents of fullchain.pem
sudo vi /etc/ocserv/server-key.pem   # contents of privkey.pem

Note: If you are targeting China, use a valid certificate. Self-signed certificates are easier to flag as suspicious TLS.

Edit the configuration

sudo vi /etc/ocserv/ocserv.conf

Main changes:

# Switch authentication from PAM to file-based auth
#auth = "pam[gid-min=1000]"
auth = "plain[/etc/ocserv/ocpasswd]"

# Connection limits
max-clients = 0
max-same-clients = 3

# Enable MTU discovery
#try-mtu-discovery = false
try-mtu-discovery = true

# Certificate paths
#server-cert = /etc/ssl/certs/ssl-cert-snakeoil.pem
#server-key = /etc/ssl/private/ssl-cert-snakeoil.key
server-cert = /etc/ocserv/server-cert.pem
server-key = /etc/ocserv/server-key.pem

# Routing (comment out all routes for full tunnel)
#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

# Cisco client compatibility
cisco-client-compat = true

# Client IP pool
ipv4-network = 192.168.10.0
ipv4-netmask = 255.255.224.0

# DNS
#dns = 192.168.1.2
dns = 1.1.1.1
dns = 8.8.8.8
dns = 8.8.4.4

Kernel parameters

sudo vi /etc/sysctl.conf

Enable the following:

net.ipv4.ip_forward=1
net.ipv4.conf.all.proxy_arp=1

Apply them:

sysctl -p

Firewall

On CentOS 7, I switched from firewalld to iptables.

# Disable firewalld
systemctl stop firewalld
systemctl mask firewalld

# Install and enable iptables
yum install -y iptables-services
systemctl start iptables.service
systemctl enable iptables.service
systemctl start ip6tables.service
systemctl enable ip6tables.service

Add rules:

sudo iptables -A INPUT -p tcp --dport 443 -j ACCEPT
sudo iptables -A INPUT -p udp --dport 443 -j ACCEPT
sudo iptables -t nat -A POSTROUTING -o eth0 -s 192.168.10.0/19 -j MASQUERADE

Note: Replace eth0 with your server’s actual network interface name.

Save the rules:

iptables-save > /etc/sysconfig/iptables

Or edit /etc/sysconfig/iptables directly:

sudo vi /etc/sysconfig/iptables
*nat
:PREROUTING ACCEPT [0:0]
:INPUT ACCEPT [0:0]
:OUTPUT ACCEPT [0:0]
:POSTROUTING ACCEPT [0:0]
-A POSTROUTING -s 192.168.10.0/19 -o eth0 -j MASQUERADE
COMMIT

*filter
:INPUT ACCEPT [0:0]
:FORWARD ACCEPT [0:0]
:OUTPUT ACCEPT [0:0]
-A INPUT -m state --state RELATED,ESTABLISHED -j ACCEPT
-A INPUT -i lo -j ACCEPT
-A INPUT -p tcp -m state --state NEW -m tcp --dport 22 -j ACCEPT
-A INPUT -p tcp -m tcp --dport 443 -j ACCEPT
-A INPUT -p udp -m udp --dport 443 -j ACCEPT
COMMIT

Restart:

service iptables restart

Add a user

sudo ocpasswd -c /etc/ocserv/ocpasswd username

Enter the password twice.

Start the service

# Stop the socket unit if you are starting manually
sudo systemctl stop ocserv.socket

# Start manually
sudo ocserv -c /etc/ocserv/ocserv.conf

Or manage it with systemd:

sudo systemctl enable ocserv
sudo systemctl start ocserv

User management

Check status

sudo occtl show status
sudo occtl show users

User operations

# Lock
sudo ocpasswd -c /etc/ocserv/ocpasswd -l username

# Unlock
sudo ocpasswd -c /etc/ocserv/ocpasswd -u username

# Delete
sudo ocpasswd -c /etc/ocserv/ocpasswd -d username

Bulk user creation with expect

If you need to add many users, an expect script is handy.

yum install -y expect

Create ex.exp:

#!/usr/bin/expect

set Id [lindex $argv 0]
set pw [lindex $argv 1]

spawn ocpasswd -c /etc/ocserv/ocpasswd ${Id}
expect {
    "Enter password:" {
        send "${pw}\n"
    }
}
expect {
    "password:" {
        send "${pw}\n"
    }
}
interact
exit 0

Run it:

expect ex.exp username password

Self-signed certificate generation

This is for environments where Let’s Encrypt is not available. For China-facing access, a real certificate is strongly recommended.

cd /etc/ocserv

Create a CA template:

sudo vi ca.tmpl
cn = "VPN CA"
organization = "example.com"
serial = 1
expiration_days = 3650
ca
signing_key
cert_signing_key
crl_signing_key

Generate the CA certificate:

sudo certtool --generate-privkey --outfile ca-key.pem
sudo certtool --generate-self-signed --load-privkey ca-key.pem --template ca.tmpl --outfile ca-cert.pem

Create a server certificate template:

sudo vi server.tmpl
cn = "vpn.example.com"
organization = "example.com"
expiration_days = 3650
signing_key
encryption_key
tls_www_server

Generate the server certificate:

sudo certtool --generate-privkey --outfile server-key.pem
sudo certtool --generate-certificate --load-privkey server-key.pem --load-ca-certificate ca-cert.pem --load-ca-privkey ca-key.pem --template server.tmpl --outfile server-cert.pem

Client connection

Cisco AnyConnect

You can use the official Cisco AnyConnect client as-is.

  • Windows / macOS / Linux: install Cisco AnyConnect
  • iOS / Android: install “Cisco AnyConnect” from the App Store or Google Play

Enter the server’s domain name and authenticate with a username and password.

OpenConnect client

The open-source client also works.

# Ubuntu / Debian
sudo apt install openconnect

# Connect
sudo openconnect vpn.example.com

Use Let’s Encrypt

Self-signed certificates are easier for GFW-style filtering to detect. A real certificate makes the server look like a normal HTTPS site.

Consider disabling DTLS

UDP traffic (DTLS) can be easier to detect. If you want to run TLS only, set the following in ocserv.conf:

udp-port = 0

ocserv version

The version in CentOS 7’s yum repositories may be old. If you need the latest release, build from source.

-> Continue with: IKEv2 (strongSwan) server setup notes

-> Summary: Comparison of VPN protocols for China-facing connectivity

References