Complete Guide to Installing and Configuring OpenVPN on Ubuntu Server from A to Z

Security tutorial - IT technology blog
Security tutorial - IT technology blog

Install OpenVPN in 5 Minutes with an Automated Script

If you need a VPN server up and running immediately without manually configuring every step, the openvpn-install script is the fastest way to get there. I use this script for staging environments or demos that need to be deployed quickly.

# Download and run the automated installation script
wget https://raw.githubusercontent.com/angristan/openvpn-install/master/openvpn-install.sh
chmod +x openvpn-install.sh
sudo bash openvpn-install.sh

The script prompts you for a few details: server IP, port, DNS, and client name. About 2–3 minutes later, you have a ready-to-import .ovpn file. That simple.

Production is a different story. When you need control over which ciphers to use, which subnets to route, and where logs go — a manual install gives you the flexibility you need. The sections below walk through every step in detail.

Manually Installing OpenVPN on Ubuntu 22.04

Step 1: Install Packages

sudo apt update
sudo apt install -y openvpn easy-rsa

Step 2: Create the Certificate Authority (CA)

Easy-RSA 3.x (bundled with Ubuntu 22.04) is a solid PKI management toolkit. I keep the CA in its own directory — makes it much easier to find when revoking certificates or signing new clients later, without it getting mixed up with the OpenVPN config.

# Create the PKI directory
make-cadir ~/openvpn-ca
cd ~/openvpn-ca

# Initialize the PKI and build the CA
./easyrsa init-pki
./easyrsa build-ca nopass

build-ca nopass creates a CA without a passphrase — so the server can restart without getting stuck waiting for a password. If this CA manages multiple critical services, drop nopass for stronger security.

Step 3: Generate the Server Certificate

# Generate the server certificate and private key
./easyrsa gen-req server nopass
./easyrsa sign-req server server

# Generate Diffie-Hellman parameters (takes about 30-60 seconds on a 2 vCPU VPS)
./easyrsa gen-dh

# Generate the TLS Auth key (protects against DDoS and replay attacks)
openvpn --genkey secret ta.key

Step 4: Copy Files to the OpenVPN Directory

sudo cp pki/ca.crt pki/private/server.key pki/issued/server.crt /etc/openvpn/server/
sudo cp pki/dh.pem ta.key /etc/openvpn/server/

Step 5: Create the Server Configuration File

sudo nano /etc/openvpn/server/server.conf

The config below is what I actually run in production, refined through many deployments:

port 1194
proto udp
dev tun

ca /etc/openvpn/server/ca.crt
cert /etc/openvpn/server/server.crt
key /etc/openvpn/server/server.key
dh /etc/openvpn/server/dh.pem
tls-auth /etc/openvpn/server/ta.key 0

server 10.8.0.0 255.255.255.0
push "redirect-gateway def1 bypass-dhcp"
push "dhcp-option DNS 1.1.1.1"
push "dhcp-option DNS 8.8.8.8"

keepalive 10 120
cipher AES-256-GCM
auth SHA256

user nobody
group nogroup
persist-key
persist-tun

status /var/log/openvpn-status.log
log-append /var/log/openvpn.log
verb 3

Step 6: Enable IP Forwarding and Start the Service

# Enable IP forwarding
echo 'net.ipv4.ip_forward=1' | sudo tee -a /etc/sysctl.conf
sudo sysctl -p

# Configure iptables to forward traffic
sudo iptables -t nat -A POSTROUTING -s 10.8.0.0/8 -o eth0 -j MASQUERADE

# Start OpenVPN
sudo systemctl enable --now openvpn-server@server
sudo systemctl status openvpn-server@server

Creating Client Certificates

cd ~/openvpn-ca

# Generate a client certificate (replace "client1" with the actual name)
./easyrsa gen-req client1 nopass
./easyrsa sign-req client client1

Next, create a client1.ovpn file for the client to import:

cat > ~/client1.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
verb 3
key-direction 1
<ca>
$(cat ~/openvpn-ca/pki/ca.crt)
</ca>
<cert>
$(cat ~/openvpn-ca/pki/issued/client1.crt)
</cert>
<key>
$(cat ~/openvpn-ca/pki/private/client1.key)
</key>
<tls-auth>
$(cat ~/openvpn-ca/ta.key)
</tls-auth>
EOF

Advanced Configuration

Run OpenVPN on Port 443 TCP to Bypass Firewalls

Corporate networks, hotels, and coworking spaces often block UDP/1194. Running on TCP/443 makes your traffic look like HTTPS — most corporate firewalls will let it through without question.

# Edit in server.conf
port 443
proto tcp

The trade-off: TCP-over-TCP creates double overhead, adding roughly 20–40ms of extra latency compared to UDP depending on the route. Only switch when UDP is genuinely blocked.

Restrict Clients to Route Only Necessary Traffic (Split Tunneling)

Full tunnel redirects all traffic through the VPN — including employees watching YouTube. That wastes server bandwidth and adds unnecessary latency. Split tunneling routes only traffic destined for internal subnets through the VPN, while everything else goes directly through the user's ISP.

# Remove the redirect-gateway line and replace with a specific route
# push "redirect-gateway def1 bypass-dhcp"  # Remove this line
push "route 192.168.1.0 255.255.255.0"  # Route only the internal subnet

Revoke Certificates When Employees Leave

cd ~/openvpn-ca
./easyrsa revoke client1
./easyrsa gen-crl

# Copy the CRL into OpenVPN
sudo cp pki/crl.pem /etc/openvpn/server/

# Add to /etc/openvpn/server/server.conf if not already present
echo "crl-verify /etc/openvpn/server/crl.pem" | sudo tee -a /etc/openvpn/server/server.conf

sudo systemctl restart openvpn-server@server

Real-World Tips from Audit Experience

After auditing more than 10 servers, the same pattern keeps showing up: VPN is running, but the configuration has vulnerabilities baked in from the start. Here's the checklist I always run through during a review:

  • Avoid legacy ciphers: Stay away from BF-CBC (Blowfish) and AES-128-CBC. Use AES-256-GCM — it's an AEAD cipher that encrypts and authenticates data in a single pass, so you don't need a separate auth directive.
  • Enable tls-auth or tls-crypt: tls-auth adds an HMAC signature to every packet — invalid packets are dropped before decryption even begins. tls-crypt goes further by encrypting the TLS handshake itself. I prefer tls-crypt.
  • Use tls-version-min 1.2: Add this line to server.conf to disable TLS 1.0 and 1.1.
  • UFW Firewall: Don't forget to open the port and allow forwarding:
sudo ufw allow 1194/udp
sudo ufw allow OpenSSH

# Add to /etc/ufw/before.rules (before the *filter line)
*nat
:POSTROUTING ACCEPT [0:0]
-A POSTROUTING -s 10.8.0.0/8 -o eth0 -j MASQUERADE
COMMIT
  • One certificate per device: Use a naming convention like user_device — for example, john_laptop or john_phone. When you need to block a specific device, revoke exactly that certificate without affecting the same user's other devices.
  • Monitor logs regularly: /var/log/openvpn-status.log shows in real time who is connected and from which IP. Pair it with fail2ban to automatically block IPs with repeated authentication failures.

Testing the Connection from the Client

# Linux/macOS
sudo openvpn --config client1.ovpn

# Check your IP after connecting
curl ifconfig.me
# Should show the VPN server's IP

Windows users can use OpenVPN Connect from the Microsoft Store, macOS has Tunnelblick, and both iOS and Android have the OpenVPN Connect app — all of them import the .ovpn file the same way.

The most commonly forgotten step: after editing server.conf, always restart the service and check the logs immediately to catch errors early.

sudo systemctl restart openvpn-server@server
sudo journalctl -u openvpn-server@server -f

A working VPN doesn't mean the job is done — it's just one layer in a defense-in-depth strategy. Add SSH key-only authentication (disable password login entirely), network segmentation between VLANs, and alerts for unfamiliar IPs connecting. Combine all three and you can actually sleep soundly.

Share: