OpenConnect ocserv SSL / TLS VPN server install and setup guide

Are you looking to setup and install your own SSL / TLS VPN server which works from all over the world even with restrictive firewalls and countries then this is a good alternative for Wireguard which is easily blocked.

Tested on Debian 12. Use your own VPN subdomain or a dynamic DNS hostname and point to the IPv6 / IPv4 address of your VPN server.

Installation of OpenConnect (ocserv) VPN server.

Create a new bash file in /root/vpnsetup.sh nano /root/vpnsetup.sh and paste the content from below.

/root/vpnsetup.sh
#!/bin/bash

# Text color
RD=$(echo "\033[01;31m")
YW=$(echo "\033[33m")
GN=$(echo "\033[1;92m")
CL=$(echo "\033[m")
BFR="\\r\\033[K"
HOLD="+"
CM="${GN}✓${CL}"
CROSS="${RD}✗${CL}"

msg_info() {
local msg="$1"
echo -e " ${HOLD} ${YW}${msg}${CL}"
}

msg_ok() {
local msg="$1"
echo -e "${BFR} ${CM} ${GN}${msg}${CL}"
}

msg_error() {
local msg="$1"
echo -e "${BFR} ${CROSS} ${RD}${msg}${CL}"
}

# chmod 755 setup.sh
# ./setup.sh
clear
echo "=========================================="
echo "=========  VPN SERVER SETUP  ============="
echo "=========================================="

echo -n "Start VPN server setup? [y/N]? "
read answer
if [ "$answer" != "${answer#[Yy]}" ] ;then
echo "Starting VPN server setup"
else
echo "Exiting VPN server setup"
exit
fi
sleep 1

echo -n "Install and setup Ocserv VPN Server [y/N]? "
read answer
if [ "$answer" != "${answer#[Yy]}" ] ;then
apt install ocserv
#echo "Ocserv server installed!"
msg_ok "Ocserv server installed!"

openssl ecparam -out /etc/ocserv/server-key.pem -name prime256v1 -genkey
openssl req -new -days 365 -nodes -x509 -subj "/C=US/ST=Local/L=Local/O=Local/CN=vpn.example.com" -key /etc/ocserv/server-key.pem -out /etc/ocserv/server-cert.pem
msg_ok "Self signed TLS certificate setup done!"

IPv6Subnet=$(printf "2001:db8:%s"; openssl rand -hex 4 | sed 's/\(....\)/\1:/g; s/.$//');
IPv6Subnet+="::/64"
sed -i -e "s?#server-cert = /etc/ocserv/server-cert.pem?server-cert = /etc/ocserv/server-cert.pem?g" /etc/ocserv/ocserv.conf
sed -i -e "s?#server-key = /etc/ocserv/server-key.pem?server-key = /etc/ocserv/server-key.pem?g" /etc/ocserv/ocserv.conf
sed -i -e "s?keepalive = 32400?keepalive = 300?g" /etc/ocserv/ocserv.conf
sed -i -e "s?try-mtu-discovery = false?try-mtu-discovery = true?g" /etc/ocserv/ocserv.conf
sed -i -e "s?idle-timeout = 1200?#idle-timeout = 1200?g" /etc/ocserv/ocserv.conf
sed -i -e "s?mobile-idle-timeout = 2400?#mobile-idle-timeout = 2400?g" /etc/ocserv/ocserv.conf
sed -i -e "s?tls-priorities = \"NORMAL:%SERVER_PRECEDENCE:%COMPAT:-VERS-SSL3.0:-VERS-TLS1.0:-VERS-TLS1.1:-VERS-TLS1.3\"?#tls-priorities = \"NORMAL:%SERVER_PRECEDENCE:%COMPAT:-VERS-SSL3.0:-VERS-TLS1.0:-VERS-TLS1.1:-VERS-TLS1.3\"?g" /etc/ocserv/ocserv.conf
sed -i -e "s?#tls-priorities = \"NORMAL:%SERVER_PRECEDENCE:%COMPAT:-RSA:-VERS-SSL3.0:-ARCFOUR-128\"?tls-priorities = \"NORMAL:%SERVER_PRECEDENCE:%COMPAT:-VERS-ALL:+VERS-TLS1.3\"?g" /etc/ocserv/ocserv.conf
sed -i -e "s?ipv4-network = 192.168.1.0?ipv4-network = 10.37.54.0?g" /etc/ocserv/ocserv.conf
sed -i -e "s?#ipv6-network = fda9:4efe:7e3b:03ea::/48?ipv6-network = $IPv6Subnet?g" /etc/ocserv/ocserv.conf
sed -i -e "s?#ipv6-subnet-prefix = 128?ipv6-subnet-prefix = 128?g" /etc/ocserv/ocserv.conf
sed -i -e "s?#tunnel-all-dns = true?tunnel-all-dns = true?g" /etc/ocserv/ocserv.conf
sed -i -e "s?# dns = fc00::4be0?dns = 2606:4700:4700::1111?g" /etc/ocserv/ocserv.conf
sed -i -e "s?dns = 192.168.1.1?dns = 1.1.1.1?g" /etc/ocserv/ocserv.conf
sed -i -e "s?#route = default?route = default?g" /etc/ocserv/ocserv.conf
sed -i -e "s?route = 10.0.0.0/8?#route = 10.0.0.0/8?g" /etc/ocserv/ocserv.conf
sed -i -e "s?route = 172.16.0.0/12?#route = 172.16.0.0/12?g" /etc/ocserv/ocserv.conf
sed -i -e "s?route = 192.168.0.0/16?#route = 192.168.0.0/16?g" /etc/ocserv/ocserv.conf
sed -i -e "s?cisco-client-compat = true?cisco-client-compat = false?g" /etc/ocserv/ocserv.conf
sed -i -e "s?dtls-legacy = true?dtls-legacy = false?g" /etc/ocserv/ocserv.conf
systemctl restart ocserv
msg_ok "Ocserv config done!"
iname=$(ip route | grep default | sed -e "s/^.*dev.//" -e "s/.proto.*//" | sed 's/ //g')
echo "Configuring Nftables..."
tee > /etc/nftables.conf <<EOF
#!/usr/sbin/nft -f

flush ruleset

# ----- IPv4 -----
table ip filter {
	chain input {
		type filter hook input priority 0;
		# accept traffic originated from us
		ct state {established, related} accept
		# loopback
		iifname lo accept

		# accept all icmp
		meta l4proto icmp accept
		meta l4proto igmp accept

		# allow incoming broadcast and multicast (e.g. NTP)
		pkttype { broadcast,multicast} accept

		tcp dport { 22, 443 } accept
		udp dport { 443, 68 } accept

		meta l4proto udp reject
		meta l4proto tcp reject
		reject
	}

	chain forward {
		type filter hook forward priority 0;
		iifname "$iname" oifname "vpns*" accept;
		iifname "vpns*" oifname "$iname" accept;
	}

	chain output {
		type filter hook output priority 0;
	}
}


# ----- IPv6 -----
table ip6 filter {
	chain input {
		type filter hook input priority 0;

		# accept traffic originated from us
		ct state {established, related} accept

		# loopback
		iifname lo accept

		# accept all icmp
		meta l4proto ipv6-icmp accept
		ip6 ecn not-ect accept

		tcp dport { 22, 443 } accept
		udp dport { 443, 546 } accept

		meta l4proto udp reject
		meta l4proto tcp reject
		reject
	}

	chain forward {
		type filter hook forward priority 0;
		iifname "$iname" oifname "vpns*" accept;
		iifname "vpns*" oifname "$iname" accept;
	}

	chain output {
		type filter hook output priority 0;
	}
}

# ----- IPv4 NAT -----
table ip nat {
	chain PREROUTING {
		type nat hook prerouting priority filter; policy accept;
	}

	chain POSTROUTING {
		type nat hook postrouting priority srcnat; policy accept;
		oifname "$iname" masquerade
	}
}

# ----- IPv6 NAT -----
table ip6 nat {
	chain PREROUTING {
		type nat hook prerouting priority filter; policy accept;
	}
	chain POSTROUTING {
		type nat hook postrouting priority srcnat; policy accept;
		oifname "$iname" masquerade
	}
}
EOF
systemctl enable nftables
systemctl start nftables
# Enable forwarding
sed -i -e "s?#net.ipv4.ip_forward=1?net.ipv4.ip_forward=1?g" /etc/sysctl.conf
sed -i -e "s?#net.ipv6.conf.all.forwarding=1?net.ipv6.conf.all.forwarding=1?g" /etc/sysctl.conf
echo "net.ipv6.conf.$iname.accept_ra=2" >> /etc/sysctl.conf
sysctl -p
#echo "Ocserv setup done!"
msg_ok "Ocserv setup done!"
else
msg_info "Skipped"
fi
#sleep 1

echo -n "Add VPN user [y/N]? "
read answer
if [ "$answer" != "${answer#[Yy]}" ] ;then
echo -n "Enter Username: "
read username
ocpasswd -c /etc/ocserv/passwd $username
#echo "New user added!"
msg_ok "New user added!"
answer=yes
while [ "$answer" = yes ]
do
echo -n "Add another user? [y/N]? "
read answer
if [ "$answer" != "${answer#[Yy]}" ] ;then
echo -n "Enter Username: "
read username
ocpasswd -c /etc/ocserv/passwd $username
#echo "New user added!"
msg_ok "New user added!"
sleep 1
answer=yes
fi
done
else
msg_info "Skipped"
fi
#sleep 1

echo -n "Delete VPN user [y/N]? "
read answer
if [ "$answer" != "${answer#[Yy]}" ] ;then
echo -n "Enter Username: "
read username
ocpasswd -c /etc/ocserv/passwd -d $username
echo "$username user deleted!"
else
msg_info "Skipped"
fi
#sleep 1

clear
echo "=========================================="
echo "======== VPN SERVER SETUP DONE  =========="
echo "=========================================="

Give execution permission to the bash script chmod +x /root/vpnsetup.sh

Start the installation by running the command bash /root/vpnsetup.sh

To add or remove more users run the setup file again just skip installing the server again. The script above generates a self signed certificate and when you connect to your VPN server you will see warning before you connect to it which you can ignore if you are OK with it. If you want a valid certificate then read below.

LetsEncrypt certificates

It is highly recommended to use a valid SSL/TLS certificate to secure your server, for example LetsEncrypt Change the paths for certificate to LetsEncrypt.

Install acme.sh

curl https://raw.githubusercontent.com/acmesh-official/acme.sh/master/acme.sh | sh -s -- --install-online -m email@example.com --home ~/acme.sh

mkdir -p /etc/LetsEncrypt/vpn

acme.sh --issue --dns dns_acmedns -d 'vpn.example.com' --cert-file /etc/LetsEncrypt/vpn/cert.pem --key-file /etc/LetsEncrypt/vpn/key.pem --fullchain-file /etc/LetsEncrypt/vpn/fullchain.pem --reloadcmd "systemctl reload ocserv" --preferred-chain "ISRG Root X2" --keylength ec-256 --syslog 6

Now edit the paths for the correct LetsEncrypt certificates in the config file /etc/ocserv/ocserv.conf

server-cert = /etc/LetsEncrypt/vpn/fullchain.pem

server-key = /etc/LetsEncrypt/vpn/key.pem

OpenConnect Clients

Android: link

Linux: link

Windows: link

iOS: link

Let me know if you have any comments or if there is any error in this guide.