Introduction
OpenVPN is the most widely deployed open-source VPN. It’s slower than WireGuard but works through almost any firewall (TCP port 443 looks like HTTPS), supports complex authentication (LDAP, RADIUS, 2FA), and has clients for every platform. This guide sets up a production-ready OpenVPN server.
Prerequisites: Ubuntu 22.04 server with a public IP, sudo access.
Step 1: Install OpenVPN and easy-rsa
sudo apt update
sudo apt install openvpn easy-rsa
# Verify
openvpn --version
Step 2: Set Up PKI (Certificate Authority)
# Create PKI directory
make-cadir /etc/openvpn/easy-rsa
cd /etc/openvpn/easy-rsa
# Configure PKI variables
cat > vars << 'EOF'
set_var EASYRSA_REQ_COUNTRY "US"
set_var EASYRSA_REQ_PROVINCE "California"
set_var EASYRSA_REQ_CITY "San Francisco"
set_var EASYRSA_REQ_ORG "My Company"
set_var EASYRSA_REQ_EMAIL "[email protected]"
set_var EASYRSA_REQ_OU "IT"
set_var EASYRSA_ALGO "ec"
set_var EASYRSA_CURVE "prime256v1"
set_var EASYRSA_CA_EXPIRE 3650
set_var EASYRSA_CERT_EXPIRE 825
EOF
# Initialize PKI
./easyrsa init-pki
# Create CA (Certificate Authority)
./easyrsa build-ca nopass
# Enter a Common Name like "My VPN CA"
# Create server certificate
./easyrsa gen-req server nopass
./easyrsa sign-req server server
# Create TLS auth key (prevents DoS attacks)
openvpn --genkey secret /etc/openvpn/ta.key
# Copy files to OpenVPN directory
cp pki/ca.crt /etc/openvpn/
cp pki/issued/server.crt /etc/openvpn/
cp pki/private/server.key /etc/openvpn/
# Set permissions
chmod 600 /etc/openvpn/server.key /etc/openvpn/ta.key
Step 3: Create Server Configuration
sudo nano /etc/openvpn/server.conf
# /etc/openvpn/server.conf โ production-ready configuration
# Network
port 1194
proto udp # use tcp if UDP is blocked: proto tcp
dev tun
# Certificates
ca /etc/openvpn/ca.crt
cert /etc/openvpn/server.crt
key /etc/openvpn/server.key
tls-auth /etc/openvpn/ta.key 0
# Modern cipher suite (OpenVPN 2.5+)
cipher AES-256-GCM
auth SHA256
tls-version-min 1.2
tls-cipher TLS-ECDHE-ECDSA-WITH-AES-256-GCM-SHA384:TLS-ECDHE-RSA-WITH-AES-256-GCM-SHA384
# Disable old/weak ciphers
tls-groups prime256v1:secp384r1
ncp-ciphers AES-256-GCM:AES-128-GCM
# Network topology
server 10.8.0.0 255.255.255.0
topology subnet
# Push routes to clients
push "redirect-gateway def1 bypass-dhcp"
push "dhcp-option DNS 1.1.1.1"
push "dhcp-option DNS 8.8.8.8"
# Keep connections alive
keepalive 10 120
# Security
user nobody
group nogroup
persist-key
persist-tun
# Logging
status /var/log/openvpn-status.log
log-append /var/log/openvpn.log
verb 3
# Performance
sndbuf 393216
rcvbuf 393216
push "sndbuf 393216"
push "rcvbuf 393216"
Step 4: Enable IP Forwarding and NAT
# Enable IP forwarding
echo "net.ipv4.ip_forward=1" | sudo tee -a /etc/sysctl.conf
sudo sysctl -p
# Set up NAT (replace eth0 with your network interface)
sudo iptables -t nat -A POSTROUTING -s 10.8.0.0/24 -o eth0 -j MASQUERADE
sudo iptables -A FORWARD -i tun0 -j ACCEPT
sudo iptables -A FORWARD -o tun0 -j ACCEPT
# Make iptables rules persistent
sudo apt install iptables-persistent
sudo netfilter-persistent save
Step 5: Start OpenVPN
sudo systemctl enable --now openvpn@server
sudo systemctl status openvpn@server
# Check logs
sudo tail -f /var/log/openvpn.log
Step 6: Create Client Certificates
cd /etc/openvpn/easy-rsa
# Create client certificate (repeat for each user)
./easyrsa gen-req alice nopass
./easyrsa sign-req client alice
# Generate client config
cat > /tmp/alice.ovpn << EOF
client
dev tun
proto udp
remote YOUR_SERVER_IP 1194
resolv-retry infinite
nobind
persist-key
persist-tun
remote-cert-tls server
cipher AES-256-GCM
auth SHA256
tls-version-min 1.2
key-direction 1
verb 3
<ca>
$(cat /etc/openvpn/ca.crt)
</ca>
<cert>
$(cat /etc/openvpn/easy-rsa/pki/issued/alice.crt)
</cert>
<key>
$(cat /etc/openvpn/easy-rsa/pki/private/alice.key)
</key>
<tls-auth>
$(cat /etc/openvpn/ta.key)
</tls-auth>
EOF
# Send alice.ovpn to the user securely
Automate Client Config Generation
#!/bin/bash
# generate-client.sh
CLIENT_NAME=$1
OPENVPN_DIR="/etc/openvpn"
EASYRSA_DIR="$OPENVPN_DIR/easy-rsa"
SERVER_IP="YOUR_SERVER_IP"
SERVER_PORT="1194"
cd "$EASYRSA_DIR"
# Generate certificate
./easyrsa gen-req "$CLIENT_NAME" nopass
./easyrsa sign-req client "$CLIENT_NAME"
# Create .ovpn file
cat > "/tmp/${CLIENT_NAME}.ovpn" << EOF
client
dev tun
proto udp
remote $SERVER_IP $SERVER_PORT
resolv-retry infinite
nobind
persist-key
persist-tun
remote-cert-tls server
cipher AES-256-GCM
auth SHA256
tls-version-min 1.2
key-direction 1
verb 3
<ca>
$(cat $OPENVPN_DIR/ca.crt)
</ca>
<cert>
$(openssl x509 -in $EASYRSA_DIR/pki/issued/${CLIENT_NAME}.crt)
</cert>
<key>
$(cat $EASYRSA_DIR/pki/private/${CLIENT_NAME}.key)
</key>
<tls-auth>
$(cat $OPENVPN_DIR/ta.key)
</tls-auth>
EOF
echo "Client config: /tmp/${CLIENT_NAME}.ovpn"
Adding Two-Factor Authentication
# Install Google Authenticator PAM module
sudo apt install libpam-google-authenticator
# Configure PAM for OpenVPN
sudo nano /etc/pam.d/openvpn
# /etc/pam.d/openvpn
auth required pam_google_authenticator.so
# Add to server.conf
plugin /usr/lib/openvpn/openvpn-plugin-auth-pam.so openvpn
# Each user runs this to set up their TOTP
google-authenticator
# Scan the QR code with Google Authenticator app
Revoking a Certificate
cd /etc/openvpn/easy-rsa
# Revoke the certificate
./easyrsa revoke alice
# Generate new CRL
./easyrsa gen-crl
# Copy CRL to OpenVPN directory
cp pki/crl.pem /etc/openvpn/
# Add to server.conf (if not already there)
echo "crl-verify /etc/openvpn/crl.pem" >> /etc/openvpn/server.conf
sudo systemctl restart openvpn@server
Performance Tuning
# Check current throughput
iperf3 -s # on server
iperf3 -c YOUR_SERVER_IP # on client through VPN
# Typical OpenVPN throughput: 100-300 Mbps
# Compare to WireGuard: 800-950 Mbps on same hardware
# Performance settings in server.conf
# Increase buffer sizes
sndbuf 393216
rcvbuf 393216
push "sndbuf 393216"
push "rcvbuf 393216"
# Use fast-io for UDP
fast-io
# Compression (only for uncompressed traffic)
# compress lz4-v2 # disabled by default โ can be a security risk (VORACLE attack)
Firewall Traversal: TCP Mode
If UDP is blocked, use TCP on port 443 (looks like HTTPS):
# server.conf changes for TCP mode
proto tcp
port 443
# Client config changes
proto tcp
remote YOUR_SERVER_IP 443
# Allow port 443 through firewall
sudo ufw allow 443/tcp
Monitoring
# View connected clients
sudo cat /var/log/openvpn-status.log
# Real-time log
sudo tail -f /var/log/openvpn.log
# Count connected clients
grep "^CLIENT_LIST" /var/log/openvpn-status.log | wc -l
# Check for failed auth attempts
grep "AUTH_FAILED" /var/log/openvpn.log | tail -20
Troubleshooting
# Client can't connect
sudo journalctl -u openvpn@server -f
# TLS handshake failure
# โ Check that ta.key direction matches (0 on server, 1 on client)
# โ Check cipher compatibility
# No internet through VPN
# โ Check IP forwarding: cat /proc/sys/net/ipv4/ip_forward (should be 1)
# โ Check NAT rules: sudo iptables -t nat -L
# Slow performance
# โ Switch to UDP if using TCP
# โ Check server CPU: top (look for openvpn process)
# โ Consider WireGuard for better performance
Comments