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-dtls
If 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 iptables
Generate 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=false
Finally restart ocserv to update the changes
sudo systemctl restart ocserv
Set 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 restart
If 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 -p
Firewall
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 MASQUERADE
To make the table rules persistent across reboots using this
apt-get -y install iptables-persistent
dpkg-reconfigure iptables-persistent
Using 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
COMMIT
Add 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 ACCEPT
Finally 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.