Andrew Mercer

OpenVPN Client Configuration

Part of the OpenVPN Comprehensive Guide.
Covers issuing a new client certificate and setting the client up on
Linux, Windows, and macOS. Assumes a server is already up per
openvpn-server-configuration.md.

1. Issue a client certificate

Run on the CA/server host, using EasyRSA (see
openvpn-installation.md for setup):

cd /etc/openvpn/easy-rsa/easyrsa3
./easyrsa gen-req amercer-pc1 nopass
./easyrsa sign-req client amercer-pc1

That produces:

  • pki/private/amercer-pc1.key — the client's private key, never leaves
    this machine unencrypted
  • pki/issued/amercer-pc1.crt — the signed client cert

The CN (amercer-pc1 here) is the client's identity — it's what
client-config-dir matches on (see
openvpn-server-configuration.md) and
what shows up in logs and the CRL when you revoke it later.

2. Build a single-file client config

Rather than distributing separate .crt/.key/ca.crt/tls-crypt.key
files (what the original notes did, with per-OS path munging), OpenVPN
supports inlining everything into one .ovpn file. One file to transfer
means one thing to keep secret and no path-separator headaches between
Linux and Windows.

# amercer-pc1.ovpn
client
dev tun
proto udp
remote vpn.example.net 1194
resolv-retry infinite
nobind
persist-key
persist-tun

remote-cert-tls server
verify-x509-name "vpn.example.net" name

data-ciphers AES-256-GCM
tls-version-min 1.2
verb 3

<ca>
-----BEGIN CERTIFICATE-----
... contents of ca.crt ...
-----END CERTIFICATE-----
</ca>

<cert>
-----BEGIN CERTIFICATE-----
... contents of amercer-pc1.crt ...
-----END CERTIFICATE-----
</cert>

<key>
-----BEGIN PRIVATE KEY-----
... contents of amercer-pc1.key ...
-----END PRIVATE KEY-----
</key>

<tls-crypt>
-----BEGIN OpenVPN Static key V1-----
... contents of tls-crypt.key ...
-----END OpenVPN Static key V1-----
</tls-crypt>

Notes on what changed from the old client configs:

  • verify-x509-name now uses the simple "hostname" name form instead of
    matching the full subject DN string ('C=CA, ST=Ontario, ... CN=...').
    The full-DN form still works, but it's brittle — it breaks the moment any
    field in the server cert's subject changes, even irrelevant ones. Matching
    just the CN is what you actually care about.
  • remote-cert-tls server added — makes sure the cert presented is
    specifically flagged as a server cert and not just any cert signed by
    the same CA (defense against a compromised client cert being used to
    impersonate the server).
  • tls-auth ... 1 replaced with <tls-crypt> inline block, matching the
    server side.
  • comp-lzo dropped, matching the server.
  • No more OS-specific backslash-escaped Windows paths — the inline
    <ca>/<cert>/<key>/<tls-crypt> blocks are identical across every
    platform.

Getting the config to the client securely

The original notes' zip-and-encrypt-and-email approach is a reasonable
stopgap but has no delivery confirmation and leaves a copy of a client
private key sitting in a mail spool/inbox indefinitely. Better options, in
rough order of setup effort:

  • Hand it over via an existing encrypted channel you already trust (e.g.
    scp/rsync over SSH to the target machine directly).
    bash scp amercer-pc1.ovpn amercer@pc1:.local/openvpn/my_vpn.ovpn
  • A password-manager's secure-note/file-sharing feature, if you have one.
  • If email is genuinely the only channel available, encrypt to the
    recipient's PGP key rather than a shared zip password.

3. Linux

NetworkManager (GUI/desktop)

Most desktop Linux installs have the network-manager-openvpn plugin.
Import directly:

sudo apt install network-manager-openvpn-gnome   # or the KDE/GNOME equivalent
nmcli connection import type openvpn file amercer-pc1.ovpn
nmcli connection up amercer-pc1

Command line / headless

mkdir -p ~/.local/openvpn
cp amercer-pc1.ovpn ~/.local/openvpn/

sudo openvpn --config ~/.local/openvpn/amercer-pc1.ovpn

For anything that needs to survive reboots or run unattended, see
openvpn-systemd-service.md rather than
running this by hand each time.

4. Windows

Current OpenVPN Windows installers (get them from
https://openvpn.net/community-downloads/) run fine on any supported
Windows version without the compatibility-mode workarounds the old notes
needed for Windows 7 — install as Administrator and move on.

  1. Install the OpenVPN GUI/Connect client from the link above.
  2. Drop amercer-pc1.ovpn into C:\Program Files\OpenVPN\config\ (or
    import it directly from the GUI's "Import file" option — no need to
    hand-edit it in a text editor first, since it's already a complete
    single-file config).
  3. Right-click the OpenVPN tray icon → select the profile → Connect.

If you have multiple profiles, the tray menu lets you pick which one to
bring up. If a profile won't reconnect after you've connected/disconnected
several others in the same session, restarting the OpenVPN GUI process
clears it up — this is a client quirk, not a server-side issue.

5. macOS

Tunnelblick (https://tunnelblick.net) or the official OpenVPN Connect
client both import a .ovpn file directly (double-click it with
Tunnelblick installed, or use Connect's import option). No manual
certificate wrangling needed given the single-file config above.

6. Revoking a client

When a laptop is lost or someone leaves, revoke the cert rather than just
deleting the .ovpn file (which does nothing server-side):

cd /etc/openvpn/easy-rsa/easyrsa3
./easyrsa revoke amercer-pc1
./easyrsa gen-crl
cp pki/crl.pem /etc/openvpn/easy-rsa/easyrsa3/pki/crl.pem   # wherever server.conf's crl-verify points

Full detail on CRL behavior and what a revoked connection attempt looks
like in the logs is in
openvpn-security-hardening.md.