VPN 📖 30 min read

OpenVPN Cloud Deployment

OpenVPN isn't the fastest or the simplest VPN protocol anymore. But it runs on everything, every corporate firewall allows TCP 443, and every client — Windows, Mac, iOS, Android, Linux — has supported it for over a decade. That's why you're here. This guide walks through deploying OpenVPN on a cloud server, from certificate generation to client configuration, with both the quick Docker path and the full manual setup.

When to use OpenVPN instead of WireGuard:

  • Corporate firewalls that block UDP — WireGuard only speaks UDP. If your network's firewall drops everything except TCP 80 and 443, WireGuard won't connect at all. OpenVPN on TCP 443 disguises itself as HTTPS traffic and passes through.
  • Legacy client compatibility — You're supporting devices running older operating systems, embedded systems, or managed corporate laptops where you can't install WireGuard. OpenVPN clients have been shipping for 15+ years and are available on basically every platform.
  • TCP fallback is a hard requirement — Some environments (hotel WiFi, airport networks, certain countries) actively interfere with UDP. If your users need a connection that works even on the most hostile networks, OpenVPN's TCP mode is the answer.

📋 What I actually use this for:

One of my clients runs a corporate network that blocks all UDP and only allows outbound TCP on ports 80, 443, and 8080. WireGuard is dead on arrival there. I keep an OpenVPN server running on TCP 443 on a $5/month VPS specifically for when I need to work from their offices. It also gets occasional use from a few countries that actively block WireGuard's UDP traffic at the ISP level — OpenVPN on 443 slips through because it looks identical to regular HTTPS.

The Easy Way: Docker with kylemanna/openvpn

Using kylemanna/openvpn (Recommended)

This Docker image wraps the certificate generation and server configuration into a few commands. If you don't need fine-grained control over the PKI, start here:

# Create volume for config
docker volume create --name ovpn-data

# Generate config
docker run -v ovpn-data:/etc/openvpn --rm kylemanna/openvpn ovpn_genconfig -u udp://YOUR_SERVER_IP

# Initialize PKI
docker run -v ovpn-data:/etc/openvpn --rm -it kylemanna/openvpn ovpn_initpki

# Start the server
docker run -v ovpn-data:/etc/openvpn -d -p 1194:1194/udp --cap-add=NET_ADMIN kylemanna/openvpn

# Generate a client configuration
docker run -v ovpn-data:/etc/openvpn --rm -it kylemanna/openvpn easyrsa build-client-full CLIENTNAME nopass
docker run -v ovpn-data:/etc/openvpn --rm kylemanna/openvpn ovpn_getclient CLIENTNAME > CLIENTNAME.ovpn

That .ovpn file contains everything a client needs — certificates, keys, and connection settings in one file. Send it to the client device and import it.

Manual Installation

Install OpenVPN and Easy-RSA

# Ubuntu/Debian
sudo apt update
sudo apt install openvpn easy-rsa

Set Up Certificate Authority

Easy-RSA is unnecessarily complicated for what it does. All you actually need is a CA certificate, a server certificate, and client certificates — three things that OpenSSL can do in about five commands. Instead, Easy-RSA gives you a multi-step workflow with its own directory structure, its own variable files, and its own terminology. That said, it's what OpenVPN's documentation recommends, and it does handle revocation lists properly. So here we are.

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

# Edit vars file
nano vars

Set your variables:

set_var EASYRSA_REQ_COUNTRY "US"
set_var EASYRSA_REQ_PROVINCE "California"
set_var EASYRSA_REQ_CITY "San Francisco"
set_var EASYRSA_REQ_ORG "MyOrg"
set_var EASYRSA_REQ_EMAIL "[email protected]"
set_var EASYRSA_REQ_OU "Community"
set_var EASYRSA_ALGO "ec"
set_var EASYRSA_DIGEST "sha512"

Initialize and build CA:

./easyrsa init-pki
./easyrsa build-ca

Generate Server Certificate

./easyrsa gen-req server nopass
./easyrsa sign-req server server

Generate Diffie-Hellman Parameters

./easyrsa gen-dh

This generates a 2048-bit DH parameter file. Expect it to take a few minutes depending on your server's CPU.

Generate TLS Auth Key

openvpn --genkey secret ta.key

Copy Certificates to OpenVPN Directory

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

Server Configuration

sudo nano /etc/openvpn/server/server.conf
port 1194
proto udp
dev tun

ca ca.crt
cert server.crt
key server.key
dh dh.pem

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

tls-auth ta.key 0
cipher AES-256-GCM
auth SHA256

user nobody
group nogroup

persist-key
persist-tun

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

Enable IP Forwarding

Without IP forwarding, your VPN clients will connect but have no internet access. This is the single most common cause of the "connected but can't reach anything" problem.

echo "net.ipv4.ip_forward=1" | sudo tee -a /etc/sysctl.conf
sudo sysctl -p

Configure Firewall

# NAT rules
sudo iptables -t nat -A POSTROUTING -s 10.8.0.0/24 -o eth0 -j MASQUERADE

# Allow VPN traffic
sudo ufw allow 1194/udp
sudo ufw allow OpenSSH
sudo ufw enable

Make iptables rules survive a reboot:

sudo apt install iptables-persistent
sudo netfilter-persistent save

Start the Server

sudo systemctl start openvpn-server@server
sudo systemctl enable openvpn-server@server
sudo systemctl status openvpn-server@server

Generate Client Configurations

cd ~/openvpn-ca
./easyrsa gen-req client1 nopass
./easyrsa sign-req client client1

Create the client configuration file. Paste the actual contents of each certificate and key file between the XML-style tags:

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
key-direction 1
verb 3


[paste ca.crt contents]



[paste client1.crt contents]



[paste client1.key contents]



[paste ta.key contents]

Client Setup

  • Windows/Mac: Download OpenVPN Connect, import.ovpn file
  • Linux: sudo openvpn --config client.ovpn
  • iOS/Android: OpenVPN Connect app, import config

TCP Mode for Restrictive Networks

This is the main reason most people deploy OpenVPN in 2026. Change two lines in the server config and two in the client config:

Server config changes:

port 443
proto tcp

Client config changes:

proto tcp
remote YOUR_SERVER_IP 443

TCP adds overhead compared to UDP — expect 10-20% lower throughput and slightly higher latency due to TCP-over-TCP. But it works on networks where nothing else will.

When Things Go Wrong

Check Server Logs

sudo tail -f /var/log/openvpn/openvpn.log

Client Can't Connect

  • Is the port open? Check firewall (cloud and host level)
  • Are certificates valid? Check dates
  • Is the server running? systemctl status openvpn-server@server

Connected But No Internet

  • IP forwarding enabled?
  • NAT rules in place?
  • DNS being pushed correctly?

Conclusion

If your use case is on the list above — corporate firewalls blocking UDP, legacy clients that can't run WireGuard, or networks that require TCP fallback — OpenVPN is the right choice. The setup takes longer, Easy-RSA adds unnecessary friction, and the throughput is lower. But it connects where WireGuard can't, and that's the only thing that matters when you're sitting behind a restrictive firewall with work to do.

If your use case isn't on that list, use WireGuard.

💬 Comments