Skip to content

Last updated: 2026-02-11

OpenVPN TLS/SSL Configuration Guide

This guide provides recommended TLS/SSL settings for OpenVPN. OpenVPN uses TLS for its control channel (key exchange, authentication) and separate symmetric encryption for the data channel (tunnel traffic). Both channels need to be configured securely.

Prerequisites

PKI Setup

OpenVPN requires a full PKI. Use easy-rsa to generate the necessary certificates:

# Initialize PKI
easyrsa init-pki
easyrsa build-ca
easyrsa gen-req server nopass
easyrsa sign-req server server
easyrsa gen-dh

# Generate TLS auth key (OpenVPN 2.5+: --genkey tls-crypt ta.key)
openvpn --genkey secret ta.key

Copy the resulting files to your OpenVPN server directory:

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

Path note: On RHEL/CentOS, the server config directory is /etc/openvpn/server/ and the service is openvpn-server@server. On Debian/Ubuntu, the config directory is /etc/openvpn/ and the service is openvpn@server.

Control Channel (TLS) Configuration

The control channel uses TLS to authenticate the server and clients and to negotiate encryption keys.

TLS Protocol Version

Set the minimum TLS version to 1.2:

tls-version-min 1.2

Control Channel Cipher Suites

Configure strong cipher suites for the TLS control channel. OpenVPN uses IANA-style cipher names with a TLS- prefix for TLS 1.2:

tls-cipher TLS-ECDHE-ECDSA-WITH-AES-256-GCM-SHA384:TLS-ECDHE-RSA-WITH-AES-256-GCM-SHA384:TLS-ECDHE-ECDSA-WITH-AES-128-GCM-SHA256:TLS-ECDHE-RSA-WITH-AES-128-GCM-SHA256:TLS-ECDHE-ECDSA-WITH-CHACHA20-POLY1305-SHA256:TLS-ECDHE-RSA-WITH-CHACHA20-POLY1305-SHA256

For TLS 1.3 cipher suites (OpenVPN 2.5.1+):

tls-ciphersuites TLS_AES_256_GCM_SHA384:TLS_CHACHA20_POLY1305_SHA256:TLS_AES_128_GCM_SHA256

Note: On OpenVPN 2.4, tls-ciphersuites is not supported. This directive requires OpenVPN 2.5+ with OpenSSL 1.1.1+ for TLS 1.3 support.

TLS Authentication

Use tls-crypt to add an additional layer of authentication and encryption to the control channel. This prevents unauthenticated clients from even initiating a TLS handshake:

tls-crypt /etc/openvpn/server/ta.key

tls-crypt is preferred over the older tls-auth because it encrypts control channel packets in addition to authenticating them, hiding certificate metadata.

Data Channel Configuration

The data channel carries the actual tunnel traffic. OpenVPN 2.5+ uses data-ciphers to negotiate the data channel cipher.

Data Channel Ciphers

data-ciphers AES-256-GCM:AES-128-GCM:CHACHA20-POLY1305

Note: On OpenVPN 2.4 (shipped with RHEL 8, early SLES 15), data-ciphers and data-ciphers-fallback are not available, and tls-ciphersuites (TLS 1.3) is not supported. Use the following 2.4-compatible equivalents instead:

cipher AES-256-GCM
ncp-ciphers AES-256-GCM:AES-128-GCM

This allows the server and client to negotiate the best available AEAD cipher. All three options provide strong authenticated encryption.

Set a fallback cipher for compatibility with older clients (OpenVPN 2.4 and earlier):

data-ciphers-fallback AES-256-GCM

HMAC Authentication

For the control channel, set the HMAC digest:

auth SHA256

For data channel AEAD ciphers (GCM, POLY1305), the auth setting is used only for the control channel HMAC. AEAD ciphers handle their own authentication.

Certificate and Key Settings

ca /etc/openvpn/server/ca.crt
cert /etc/openvpn/server/server.crt
key /etc/openvpn/server/server.key
dh /etc/openvpn/server/dh.pem

ECDH Curve

Specify the elliptic curve for ECDHE key exchange:

ecdh-curve secp384r1

Certificate Revocation

Point to a CRL to revoke compromised client certificates:

crl-verify /etc/openvpn/server/crl.pem

Additional Security Settings

# Run as unprivileged user after initialization
user nobody
group nogroup

Note: On RHEL/CentOS and SLES, the group nogroup does not exist. Use group nobody instead.

# Persist key material and tunnel device across restarts
persist-key
persist-tun

# Limit client certificate types (prevent using a client cert as a server cert)
remote-cert-tls client

Complete Server Configuration

# Network
port 1194
proto udp
dev tun

# Certificates and keys
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-crypt /etc/openvpn/server/ta.key

# TLS control channel
tls-version-min 1.2
tls-cipher TLS-ECDHE-ECDSA-WITH-AES-256-GCM-SHA384:TLS-ECDHE-RSA-WITH-AES-256-GCM-SHA384:TLS-ECDHE-ECDSA-WITH-AES-128-GCM-SHA256:TLS-ECDHE-RSA-WITH-AES-128-GCM-SHA256:TLS-ECDHE-ECDSA-WITH-CHACHA20-POLY1305-SHA256:TLS-ECDHE-RSA-WITH-CHACHA20-POLY1305-SHA256
tls-ciphersuites TLS_AES_256_GCM_SHA384:TLS_CHACHA20_POLY1305_SHA256:TLS_AES_128_GCM_SHA256  # OpenVPN 2.5+; remove on 2.4
ecdh-curve secp384r1
auth SHA256

# Data channel
# OpenVPN 2.4 (RHEL 8): replace with "cipher AES-256-GCM" and "ncp-ciphers AES-256-GCM:AES-128-GCM"
data-ciphers AES-256-GCM:AES-128-GCM:CHACHA20-POLY1305
data-ciphers-fallback AES-256-GCM

# Network settings
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 1.0.0.1"

# Security
user nobody
group nogroup    # RHEL/CentOS and SLES: use "group nobody" instead
persist-key
persist-tun
remote-cert-tls client

# Logging
verb 3

Client Configuration

The client configuration mirrors the server's TLS and cipher settings:

client
dev tun
proto udp
remote vpn.example.com 1194

# Certificates
ca ca.crt
cert client.crt
key client.key
tls-crypt ta.key

# TLS settings
tls-version-min 1.2
tls-cipher TLS-ECDHE-ECDSA-WITH-AES-256-GCM-SHA384:TLS-ECDHE-RSA-WITH-AES-256-GCM-SHA384:TLS-ECDHE-ECDSA-WITH-AES-128-GCM-SHA256:TLS-ECDHE-RSA-WITH-AES-128-GCM-SHA256:TLS-ECDHE-ECDSA-WITH-CHACHA20-POLY1305-SHA256:TLS-ECDHE-RSA-WITH-CHACHA20-POLY1305-SHA256
tls-ciphersuites TLS_AES_256_GCM_SHA384:TLS_CHACHA20_POLY1305_SHA256:TLS_AES_128_GCM_SHA256  # OpenVPN 2.5+; remove on 2.4
# OpenVPN 2.4 (RHEL 8): replace data-ciphers with "cipher AES-256-GCM" and "ncp-ciphers AES-256-GCM:AES-128-GCM"
data-ciphers AES-256-GCM:AES-128-GCM:CHACHA20-POLY1305
auth SHA256

remote-cert-tls server
persist-key
persist-tun
verb 3

Verification

Start the server and check the logs:

systemctl start openvpn-server@server
journalctl -u openvpn-server@server -f

Verify the negotiated cipher in the server log. You should see lines like:

Data Channel: using negotiated cipher 'AES-256-GCM'
Control Channel: TLSv1.3, cipher TLSv1.3 TLS_AES_256_GCM_SHA384

Test the connection from a client and verify encryption:

openvpn --config client.conf