linuxlab.io
Tutorials▾
  • Linux & networking
    File system, processes, TCP/IP, BGP and OSPF
    →
  • Terraform & IaC
    HCL, state, plan/apply on a LocalStack sandbox
    →
  • Git & GitHub
    Object model, plumbing, branching, GitHub Actions
    →
All tutorials →
PricingAboutSign inCreate account
/
  • Introduction
  • Lessons
  • How it works
  • Simulator
  • Knowledge base
  • Interview prep
Index
Categories
All entries
Footer
linuxlab-TutorialsPricingAboutPrivacy & cookies
Copyright © 2026 LinuxLab. All rights reserved.
home/linux/kb/Protocols/openvpn

kb/protocols ── Protocols ── intermediate

OpenVPN: TLS-based VPN

OpenVPN is a userspace TLS VPN built on X.509 certificates. Modes: tun (L3, default) or tap (L2). Supports UDP/TCP, push routes, per-user authentication, and TCP-443 as HTTPS camouflage. Heavier than [[wireguard|WG]].

view as markdownaka: open-vpn, openvpn-server, openvpn-client

Why OpenVPN

In 2002, OpenVPN delivered what did not exist before: a VPN over TLS on top of UDP/TCP without IPsec complexity. It remains the standard for:

  • Corp VPN with per-user certificates and LDAP/RADIUS authentication
  • TCP-443 camouflage (looks like HTTPS, passes through DPI firewalls where WireGuard and IPsec are blocked)
  • Site-to-site with push routes and dynamic IP assignment to clients
  • L2 bridging via tap mode (when you need a single broadcast domain across the tunnel)

Drawbacks compared to [[wireguard|WireGuard]]:

  • Userspace, slower, more CPU usage
  • Configuration is more complex, you must generate certificates
  • One process per server (not one per peer as in WG)

tun vs tap

tun (L3): VPN sees IP packets        -- default, ~99% of cases
tap (L2): VPN sees Ethernet frames   -- when you need a single broadcast domain
  • tun does IP routing between subnets. More efficient (~1500 bytes/frame).
  • tap is bridge-in-bridge. Required for DHCP/Wake-on-LAN/non-IP protocols. Client support is weak on mobile (Android/iOS do not support tap).

If you are unsure which to pick, use tun.

Certificates with easy-rsa

bash
apt install easy-rsa openvpn
cd /usr/share/easy-rsa
./easyrsa init-pki
./easyrsa build-ca                              # password for the CA key
./easyrsa gen-dh                                # Diffie-Hellman params
./easyrsa build-server-full vpn.example.com nopass
./easyrsa build-client-full client1 nopass
# tls-crypt key to protect the handshake (not part of easy-rsa, generated by openvpn)
openvpn --genkey secret /etc/openvpn/server/tls-crypt.key

Files:

  • pki/ca.crt, the public CA certificate
  • pki/issued/<name>.crt, issued certificate
  • pki/private/<name>.key, private key
  • pki/dh.pem, DH params
  • tls-crypt.key, symmetric key for encrypting the handshake

Server config

/etc/openvpn/server/server.conf:

conf
port 1194
proto udp
dev tun
topology subnet
ca       ca.crt
cert     server.crt
key      server.key
dh       dh.pem
tls-crypt tls-crypt.key
server 10.8.0.0 255.255.255.0          # address pool for clients
ifconfig-pool-persist ipp.txt           # remember which IP belongs to which client
push "redirect-gateway def1 bypass-dhcp"   # full-tunnel
push "dhcp-option DNS 1.1.1.1"
push "dhcp-option DNS 8.8.8.8"
keepalive 10 120                        # ping every 10s, timeout 120s
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
explicit-exit-notify 1

Start the service:

bash
systemctl enable --now openvpn-server@server

Remember to enable ip-forwarding and [[cmd-iptables|MASQUERADE]] for the pushed full-tunnel to work.

Client config

client.ovpn is a single file with certificates embedded inline:

conf
client
dev tun
proto udp
remote vpn.example.com 1194
resolv-retry infinite
nobind
persist-key
persist-tun
remote-cert-tls server
cipher AES-256-GCM
auth SHA256
verb 3
<ca>
-----BEGIN CERTIFICATE-----
... ca.crt ...
-----END CERTIFICATE-----
</ca>
<cert>
... client.crt ...
</cert>
<key>
... client.key ...
</key>
<tls-crypt>
... tls-crypt.key ...
</tls-crypt>

One file is all you hand to the user. It imports into every client app (Tunnelblick, OpenVPN Connect, NetworkManager).

tls-auth vs tls-crypt

Both protect the handshake from DDoS and passive analysis:

  • tls-auth (HMAC): a packet is dropped if it lacks an HMAC signature. The older option.
  • tls-crypt (encryption): the handshake is encrypted with this key. From the outside, you cannot even tell it is OpenVPN traffic. Prefer this.

Since 2.5, tls-crypt-v2 supports per-client keys for even stronger protection.

TCP fallback

conf
proto tcp
port 443

This disguises traffic as HTTPS. Drawbacks:

  • TCP-over-TCP degrades badly under packet loss (double retransmit)
  • Slower than UDP

Use this only when UDP is blocked. You can run both servers on separate ports and have the client try UDP first.

Authentication

  • PKI cert-only (default): a client with a private key from a trusted CA is accepted
  • PKI + username/password: auth-user-pass-verify backed by PAM/RADIUS/script
  • 2FA via TOTP: through the PAM stack (pam-google-authenticator)
  • client-cert-not-required: password only (avoid this, it weakens security)

Per-user revocation:

bash
./easyrsa revoke client1
./easyrsa gen-crl                       # generate the CRL
cp pki/crl.pem /etc/openvpn/server/
# in server.conf: crl-verify crl.pem
systemctl reload openvpn-server@server

OpenVPN vs WireGuard vs IPsec

FeatureOpenVPNwireguardipsec-ike
TransportUDP/TCPUDPUDP/IP-ESP
PKI/certificatesyesnoyes
Per-user authyes (PAM/RADIUS)no (key only)yes (EAP)
Where it runsuserspacekernelkernel + userspace IKE
HTTPS camouflageyes (TCP-443)nono
Push routes/DNSyesno (via AllowedIPs)yes (mode-config)
Production maturity20+ years5+ years25+ years

Troubleshooting

  • TLS Error: TLS key negotiation failed to occur within 60 seconds: UDP/TCP is not reaching the server. Test with nc -u 1194 or nc -z 443.
  • Client connects but no internet: you forgot the redirect-gateway push or MASQUERADE on the server. Check DNS push as well.
  • Handshake fails with cipher mismatch: server and client disagree on the cipher. The old BF-CBC is deprecated. Use AES-GCM on both sides.
  • Permission denied on /dev/net/tun inside a container: you need --cap-add=NET_ADMIN --device=/dev/net/tun.
  • MTU problems (pages load slowly): a hop in the path has MTU < 1500. tun-mtu 1400 mssfix 1360 fixes this.
  • CRL has expired: CRL files have an expiry date. If clients cannot connect after months of uptime, run easyrsa gen-crl again and reload openvpn.
  • High CPU on server: many clients share one UDP socket, and OpenVPN is single-threaded. Fix with 2.6+ --server-mt or multiple processes on different ports behind a load balancer.

§ команды

bash
openvpn --genkey secret tls-crypt.key

Generate a tls-crypt key to protect the handshake from DPI

bash
easyrsa build-client-full client1 nopass

Issue a client certificate with no password protection on the key

bash
openvpn --config client.ovpn

Start the client in the foreground, useful for debugging

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

Stream server logs, the first place to check when a connection fails

bash
ss -tunlp | grep openvpn

Show which ports the server is listening on, useful for debugging firewall mismatches

bash
openssl x509 -in pki/issued/client1.crt -noout -dates -subject

Check the validity dates and subject of a client certificate

bash
easyrsa revoke client1 && easyrsa gen-crl

Revoke a client and regenerate the CRL, then copy the CRL to /etc/openvpn

§ см. также

  • wireguardWireGuard: Modern UDP VPNWireGuard is a UDP VPN built into the Linux kernel. A Curve25519 key pair, peers with AllowedIPs (both ACL and routing table). About 4000 lines of code versus millions in OpenVPN/IPsec. Flat config, no TLS, no certificates.
  • ipsec-ikeIPsec and IKEv2: the enterprise VPN standardIPsec is the L3 VPN standard. ESP encapsulates and encrypts, IKEv2 exchanges keys. Tunnel mode adds a new IP header for site-to-site; transport mode stays host-to-host. On Linux this is strongSwan.
  • tls-handshakeTLS HandshakeTLS is the encryption layer above TCP. Before data flows, both sides run a handshake: they exchange keys, verify the certificate, and agree on a cipher.
  • udp-basicsUDP: User Datagram ProtocolUDP delivers datagrams without establishing a connection, without retransmits, and without ordering guarantees. Header is 8 bytes. Use it for DNS, DHCP, QUIC, VoIP, and any case where latency matters more than reliability.
  • tcp-handshakeTCP three-way handshakeTCP connection opens with three packets: SYN from the client, SYN-ACK from the server, ACK from the client. After that the connection is Established and data transfer can begin.
Footer
linuxlab-
Copyright © 2026 LinuxLab. All rights reserved.
Tutorials
Pricing
About
Privacy & cookies