OpenVPN with easyvpn Debian 10 Buster

Create CA and certificates

mkdir /root/ca
cd /root/ca
/usr/share/easy-rsa/easyrsa init-pki
/usr/share/easy-rsa/easyrsa build-ca

Fill in the CA part (Common Name).

Next, generate server certificate. nopass option disables password.

/usr/share/easy-rsa/easyrsa build-server-full server-name nopass

Next, generate client certificate.

/usr/share/easy-rsa/easyrsa build-client-full oneplus6t nopass

Certificates are valid 3 years by default.

To remove passphrase (if you forgot nopass):

openssl rsa -in server-name.key -out server-name-nopass.key

Generate Diffie-Hellman parameters

dhparam -out /etc/openvpn/dh2048.pem 2048

Generate TA key to prevent DoS attacks and UDP port flooding

openvpn --genkey --secret ta.key

Server configuration

# grep -v -E '^(#|;|$)' /etc/openvpn/server.conf
port 1194
proto udp
dev tun
ca /root//ca/pki/ca.crt
cert /root/ca/pki/issued/usa.crt
key /root/ca/pki/private/usa-nopass.key
dh dh2048.pem
ifconfig-pool-persist ipp.txt
# this should demonstrate your local subnet. 
# I have subnets from to
push "route" 
keepalive 10 120
tls-auth ta.key 0 # This file is secret
cipher AES-256-GCM
user openvpn
group openvpn
status openvpn-status.log
verb 3
explicit-exit-notify 1
# This is a fix for t-mobile. 
tun-mtu 1450;
mssfix 1410;

Firewall configuration for incoming VPN connections

I’m still using iptables, so for me:

iptables -I INPUT 1 -p udp --dport 1194 -j ACCEPT
iptables -I FORWARD 1 -i tun1 -s -j ACCEPT
iptables -I INPUT 1 -i tun1 -s -j ACCEPT

(in my case there is no need to add outgoing FORWARD -j ACCEPT, because it’s covered with ESTABLISHED,RELATED already.)


So the complete configuration for firewall looks like this:

-A INPUT -p udp --dport 1194 -j ACCEPT

Client configuration

This is a template for client configuration that will be later used to generate configurations for individual clients:

# cat /root/scripts/openvpn/client.conf.template
dev tun
resolv-retry infinite
verb 1
keepalive 10 120
port 1194
proto udp
cipher AES-256-GCM
remote-cert-tls server
key-direction 1

And this is the script to generate client config (which works on Android and Windows):

sed -e '/<ca>/r /root/ca/pki/ca.crt' client.conf.template | sed -e "/<cert>/r /root/ca/pki/issued/$1.crt" | sed -e "/<key>/r /root/ca/pki/private/$1.key" | sed -e "/<tls-auth>/r /etc/openvpn/ta.key"

To invoke this script, you must 1) generate client cert, 2) invoke the script. Example

/usr/share/easy-rsa/easyrsa build-client-full pixel3a ## key with password
/root/scripts/openvpn/ pixel3a # generates ovpn config. copy to phone.
  • Generate client certificate
  • Invoke the script
  • Copy the generated ovpn file to your client device (android phone or windows)

Note: use password protected certificate for extra two factor.

About MTU and connection reliability

This config only sets up UDP VPN. I am setting a conservative MTU of 1450 (T-Mobile’s MTU is 1440, while AT&T is 1430). At this point I am not setting fallback to TCP (443), because it’s a bit more work (I host apache on 443, so I would need to split openvpn traffic from apache traffic, and I only have one IP address) and also results in subpar performance (congestion control issues with tunneling TCP over TCP).

It’s not clear to me why MTU discovery failed on openvpn (maybe it doesn’t do it?).

The values above seem to be confirmed with ICMP packets:

ping -M do -s 1360
PING ( 1360(1388) bytes of data.

Packet with 1360 bytes of payload, 8 bytes of ICMP echo request headers, plus 40 bytes IPv4 headers (translated to v6 headers by TMo), is 1428 bytes. But then there is extra overhead from openvpn packet encapsulation, HMACs, etc. not sure what the overhead is there.

Overall, there doesn’t seem to be one way to fix the MTU issues. Some say --tun-mtu 1500 --fragment 1300 --mssfix is a way to fix MTU related issues. I think I am going to opt to link-mtu 1440. --fragment is going to take 4bytes extra overhead. Though mssfix is good, because it fixes TCP connections.

Other useful resources:

Leave a Reply