Client
Use a recent version of OpenConnect built straight from the source (opens in a new tab). The sni flag was introduced in November 2022.
--no-dtls flag is used because DTLS only works over UDP or SCTP. Since UDP doesn't work with domain spoofing it's turned off on ocserv.
sudo openconnect <vpn-domain>:443 --sni <sni-domain> --no-dtlsIf ipv6 is enabled on the client and disabled on ocserv, all ipv6 traffic would go around the tunnel. To prevent this either disable ipv6 traffic on the client or enable it on ocserv. The prior is recommended.
Requirements
First of all disable firewalls like UFW to make sure you don't run into any unexpected issues with the initial configuration. After that point a subdomain to the server ip. A subdomain is required for this to work.
Install the necessary requirements
sudo apt install ocserv certbot iptablesGenerate SSL certificate for the vpn domain. Replace <email> and <vpn-domain>
sudo certbot certonly --standalone --preferred-challenges http --agree-tos --email <email> -d <vpn-domain>Configure Server
Configure ocserv located at /etc/ocserv/ocserv.conf.
Do these changes to the file. Leave all other rules untouched. Check if there are duplicate rules at the end of file, comment them.
# use user+pass auth when connecting using openconnect
auth = "plain[passwd=/etc/ocserv/ocpasswd]"
 
# path to the certbot SSL certificates
server-cert = /etc/letsencrypt/live/vpn.example.com/fullchain.pem
server-key = /etc/letsencrypt/live/vpn.example.com/privkey.pem
 
# comment out UDP because SNI spoofing only works over TCP
udp-port = 443
 
# set this from false to true
try-mtu-discovery = true
 
# uncomment this
tunnel-all-dns = true
 
ipv4-network = 10.12.0.0
ipv4-netmask = 255.255.255.0
 
# set DNS to google and cloudflare
dns = 8.8.8.8
dns = 1.1.1.1
 
# comment all of the route parameters
route = 10.0.0.0/8
route = 172.16.0.0/12
route = 192.168.0.0/16
route = fd00::/8
route = default
no-route = 192.168.5.0/255.255.255.0
 
# set this to false
isolate-workers=falseFinally restart ocserv to update the changes
sudo systemctl restart ocservSet ocserv user <username> and password
sudo ocpasswd -c /etc/ocserv/ocpasswd <username>Choosing TCP port
Usually the https port 443 is taken up by apache or nginx. In that case you can use a different port. For example 8443. To do that edit /etc/ocserv/ocserv.conf and change the tcp-port to 8443. Then restart ocserv.
tcp-port = 8443# restart
sudo service ocserv restartIf you're using a non usual port, make sure the firewall is configured to allow that port.
Enable ip forwarding
For ocserv to route packets between clients and the internet, IPs need to be forwarded. Edit /etc/sysctl.conf and uncomment this line
net.ipv4.ip_forward=1# save
sysctl -pFirewall
There are two ways to configure the firewall. One is through iptables itself and the other is using UFW.
Using iptables
Find the <interface> from ifconfig or ip addr. It should be something like eth0
iptables -t nat -A POSTROUTING -o <interface> -j MASQUERADETo make the table rules persistent across reboots using this
apt-get -y install iptables-persistent
dpkg-reconfigure iptables-persistentUsing UFW
Find the <interface> from ifconfig or ip addr. Edit the UFW startup config /etc/ufw/before.rules.
Add this to the end of the file.
# NAT table rules
*nat
:POSTROUTING ACCEPT [0:0]
 
# Forward traffic through eth0 - Change to match you out-interface
-A POSTROUTING -s 10.12.0.0/24 -o <interfact> -j MASQUERADE
 
# don't delete the 'COMMIT' line or these nat table rules won't
# be processed
COMMITAdd these after the allow forwarding for trusted network comment.
# allow forwarding for trusted network
-A ufw-before-forward -s 10.12.0.0/24 -j ACCEPT
-A ufw-before-forward -d 10.12.0.0/24 -j ACCEPTFinally restart UFW.
Troubleshooting
The futex facility returned an unexpected error code.If you get this error on the client side and it throws a 502 fit. Then change isolate-workers=true to isolate-workers=false in the ocserv config. The rightful solution is to upgrade ocserv. But we all know how much of a hassle that is.