This episode matures all the security topics from episodes 5 and 7 into a hardening policy: tls-crypt-v2, tls-version-min 1.2, modern ciphers with forward secrecy, and firewall and ACL for defense-in-depth.

All previous episodes built functionality. Episode 13 builds resilience. Authentication is in place, encryption is in place, but is everything configured with the right security thresholds?
Episode 13 consolidates the security topics from episodes 5 and 7 into one coherent hardening policy. You will learn to tighten the control channel with tls-crypt-v2, enforce tls-version-min 1.2, choose modern ciphers that support forward secrecy, verify identity with verify-x509-name, and close access with firewall and ACL.
The end goal is defense-in-depth: layers of protection so that if one layer fails, the next still blocks the attacker.
Episode 5 introduced tls-crypt-v2 as the evolution of pre-shared keys. For hardening, make it the standard: every client gets a unique pre-shared key that encrypts the entire control channel.
tls-crypt-v2 /etc/openvpn/server/server-crypt.key
tls-version-min 1.2
remote-cert-tls clienttls-version-min 1.2 rejects TLS handshakes below 1.2. remote-cert-tls client on the server side ensures the incoming certificate is truly a client certificate. This combination closes the control channel from observers and is hostile to weak old clients.
A certificate signed by the same CA doesn't always mean it's the one you want. To restrict acceptance to only specific certificates, use verify-x509-name:
verify-x509-name vpn.example.com name-prefixverify-x509-name vpn.example.com name-prefix ensures the server certificate's subject begins with that name. This prevents a valid certificate from the same CA but for another domain from being accepted as the server.
One hardening block for the server side consistent with episodes 5 and 7:
tls-crypt-v2 /etc/openvpn/server/server-crypt.key
tls-version-min 1.2
tls-cipher TLS-ECDHE-ECDSA-WITH-AES-256-GCM-SHA384
remote-cert-tls client
reneg-sec 1800Forward secrecy ensures that even if the server's private key leaks in the future, past sessions remain secure. This is achieved with ephemeral key exchange such as ECDHE. A server offering only ECDHE suites can't be retroactively broken.
The configuration above already uses TLS-ECDHE-... — note that ECDHE is a requirement for forward secrecy. Avoid static DH suites that don't provide this guarantee.
The data channel follows the same policy. Set a strong and firm cipher list:
ncp-ciphers AES-256-GCM:AES-128-GCM:CHACHA20-POLY1305
cipher AES-256-GCM
auth SHA256There are no CBC-mode ciphers in this list — only authenticated encryption. auth SHA256 remains for compatibility with old clients that don't support NCP.
Hardening doesn't stop at configuration. Certificates must be monitored for validity and the CA guarded from unnecessary access:
openssl x509 -in /etc/openvpn/server/server.crt -noout -datesopenssl x509 -in ... -noout -dates displays the certificate validity dates. A good habit: audit validity every month. Certificate expiry monitoring will be discussed further in episode 19.
A VPN server should serve only one port from one protocol. Shrink the attack surface with a strict firewall:
iptables -A INPUT -p udp --dport 1194 -j ACCEPT
iptables -A INPUT -p tcp --dport 22 -s 192.168.0.0/16 -j ACCEPT
iptables -A INPUT -j DROPThe rules above only open UDP 1194 and SSH from the internal network, then drop everything else. A default DROP policy is far safer than opening all ports and closing them one by one.
By default, clients in the VPN subnet can communicate with each other. If that's unwanted, block between clients while still allowing access to backend networks:
iptables -I FORWARD -i tun0 -o tun0 -j DROPThis rule rejects packets entering and leaving through tun0 — meaning clients can't reach each other, but can still reach networks routed through the server.
Above the firewall, tighten the application knobs again: max-clients from episode 11 to limit load, the management interface from episode 8 bound only to loopback, and tls-crypt-v2 to reject probes before the handshake. Every layer raises the attacker's cost.
Key takeaways:
tls-crypt-v2 encrypts the control channel and filters probes.tls-version-min 1.2 rejects weak old TLS clients.verify-x509-name restricts accepted identities.In the next episode, episode 14, we will discuss Data Channel Offload (DCO) and performance — moving data channel processing into the kernel with the ovpn-dco module, the benefits of zero-copy, multiqueue, and hardware offloading, and DCO setup and its compatibility with Windows drivers. After this episode, you're ready to optimize throughput into the 10Gbps class.