Andrew Mercer

OpenVPN Comprehensive Guide

This is the index and conceptual overview for a set of OpenVPN docs, rebuilt from
years of accumulated notes. It replaces the old scattered wiki-style pages with
one linked set, updated for modern OpenVPN (2.5/2.6) and current best practice
(EasyRSA 3, tls-crypt, AEAD ciphers, no compression).

Guide map

Doc Covers
openvpn-installation.md Installing OpenVPN from packages or source
openvpn-server-configuration.md PKI setup, server config, routing, systemd
openvpn-client-configuration.md Issuing client certs, client configs for Linux/Windows/macOS
openvpn-security-hardening.md tls-crypt, ciphers, CRLs, cert pinning, key hygiene
openvpn-systemd-service.md Autostarting the client and fixing boot-time routing
openvpn-aws-deployment.md Self-managed EC2 vs. AWS Client VPN

Read this doc first for the concepts, then jump to whichever doc matches the
task in front of you.

What OpenVPN is

OpenVPN is an open-source VPN daemon that builds an encrypted tunnel over UDP
or TCP using a TLS handshake for key negotiation, then an SSL/TLS-derived
channel for data. It's not IPsec and not WireGuard — it runs in userspace,
talks to a virtual network interface via TUN/TAP, and is scriptable at nearly
every stage of the connection lifecycle (--up, --down, --route-up,
client-connect scripts, etc.). That scriptability is why it's stuck around:
it's flexible, but that flexibility is also where most of the footguns in the
old notes came from (hand-rolled systemd units, manual route scripts, etc.).

Core architecture decisions

These are the choices you make once, up front, that everything else depends
on.

TUN vs. TAP

  • TUN (routed, layer 3) — the standard choice. Clients get an IP on a
    dedicated VPN subnet and traffic is routed. Simpler, more efficient, works
    everywhere. Use this unless you have a specific reason not to.
  • TAP (bridged, layer 2) — clients join the same Ethernet broadcast
    domain as the server's LAN. Needed for things like Wake-on-LAN across the
    tunnel or legacy broadcast-dependent protocols. More overhead, more
    fragile, and mostly obsolete now — most things people used TAP for
    (browsing "as if local," NetBIOS discovery, etc.) either don't matter
    anymore or are better solved with routing plus mDNS/reflection.

Everything in this doc set assumes TUN, which is what the original notes
used.

PKI (certificate-based) vs. static key

  • Static key (--secret) — one shared key for a single point-to-point
    tunnel, no CA, no per-client identity, no revocation. Fine for a quick
    site-to-site link between two boxes you control. Doesn't scale past two
    peers and can't be revoked without regenerating the key for everyone.
  • TLS mode with a PKI (CA + per-client certs) — what you want for
    anything with more than one client. Each client has its own identity,
    which means you can revoke a single laptop without touching anyone else,
    and you get mutual authentication (server proves who it is, client proves
    who it is) instead of a single shared secret.

The rest of this guide set uses PKI/TLS mode, matching the original
setup.

Control-channel protection: tls-auth vs. tls-crypt

The old notes used tls-auth, which HMAC-signs control-channel packets so
OpenVPN can silently drop anything not signed with the shared key (mitigates
port scanning, DoS, and TLS stack attacks before a real handshake even
starts). tls-crypt does the same thing but also encrypts the control
channel, which additionally hides certificate metadata (CNs, cert
fingerprints) from anyone sniffing the handshake. There's no real downside to
tls-crypt on a normal client/server setup — use it instead of tls-auth.
Details and the migration are in
openvpn-security-hardening.md.

What changed since the original notes

The source notes were written against OpenVPN ~2.2–2.3 conventions. A few
things have moved on enough that carrying them forward as-is would be
actively bad advice:

  • comp-lzo is gone. VPN compression combined with encryption enables
    the VORACLE attack (compression-oracle plaintext recovery, same family as
    CRIME/BREACH). Compression is disabled in the configs throughout this
    guide set. See openvpn-security-hardening.md.
  • cipher AES-256-CBC + auth SHA256 (separate encrypt + HMAC) is
    replaced with data-ciphers AES-256-GCM, an AEAD cipher that does
    authenticated encryption in one pass — faster and removes a category of
    padding-oracle style bugs. The old cipher/auth directives still work
    for backward compatibility but are legacy syntax now.
  • Manual openssl ca commands are replaced with EasyRSA 3. The original
    notes ran raw openssl req/openssl ca against a hand-maintained
    openssl.cnf. That's fragile (serial file collisions, index.txt drift,
    easy to get file permissions or extensions wrong) and EasyRSA has been the
    standard companion tool for exactly this since well before the original
    notes were written. All PKI steps in this guide set use it.
  • tls-version-min 1.2 stays, but TLS 1.3 is preferred where both ends
    support it — set tls-version-min 1.2 as the floor and let negotiation
    pick 1.3 when available, rather than pinning to 1.2.
  • Hand-rolled systemd units are replaced with the native
    [email protected] template
    that ships with the OpenVPN package,
    which sidesteps the boot-time routing race the old notes flagged as an
    unsolved TODO. See
    openvpn-systemd-service.md.

Terminology quick reference

Term Meaning
CA Certificate Authority — signs server and client certs so both sides can verify each other
CRL Certificate Revocation List — the CA's "these certs are no longer valid" list, checked by the server on connect
ta.key / tls-crypt key Pre-shared key used to authenticate (and, with tls-crypt, encrypt) the TLS control channel before the real handshake
ccd Client-config-dir — per-client config snippets (static IP, extra pushed routes) keyed by cert CN
ipp.txt IP pool persistence file — server's memory of which pooled IP a client had last time