TTR Networks

Intermediate · OpenVPN on Debian: users, routing and revocation · section 2 of 11

Install, and build a PKI

✓ Lab-tested 21 October 2026 on Debian 13.7, OpenVPN 2.6.14, easy-rsa 3.2.2, nftables 1.1.3

Installing OpenVPN on Debian is one command, and the real work is the public key infrastructure (PKI): a small certificate authority that signs a certificate for the server and one for each user. Debian packages easy-rsa for exactly this.

apt install openvpn easy-rsa

The lab image installs both at build time; these are the versions this lesson was tested with.

Build the CA and the certificates

make-cadir creates a private copy of easy-rsa in your home directory, so the CA's files never live inside a package directory. Then:

  1. init-pki creates an empty PKI.
  2. build-ca creates the CA: a private key and a self-signed certificate. Everything else trusts this key, so protect it.
  3. build-server-full server creates and signs the server's key and certificate.
  4. build-client-full alice does the same for each user. One certificate per user means one user can be removed without touching anyone else.
  5. gen-crl creates the certificate revocation list (CRL): the list of certificates the server must refuse. It starts empty.

The lab uses --batch and nopass so it can be scripted. On a real server, give the CA key a passphrase (leave out nopass on build-ca), and ideally keep the CA on a separate machine that only ever signs requests. Anyone with the CA key can mint a valid user.

The tls-crypt key

openvpn --genkey secret makes one more key, shared by the server and every user. With tls-crypt, every packet of the TLS handshake is encrypted and authenticated with it, so the server silently ignores anyone who doesn't have it: port scanners, attackers probing for TLS bugs, or someone who found an old certificate. It also hides which certificate a user presents from anyone watching the network.

The versions in this lab (real output)
root@vpn:~# cat /etc/debian_version; dpkg-query -W openvpn easy-rsa nftables
13.7
easy-rsa	3.2.2-1
nftables	1.1.3-1
openvpn	2.6.14-1+deb13u3
  • Line 2: Debian 13 (trixie).
  • Lines 3–5: easy-rsa 3.2, nftables 1.1 and OpenVPN 2.6, from Debian's own repository.
Building the CA and every certificate (real output)
root@vpn:~# make-cadir ~/easy-rsa && ls ~/easy-rsa
easyrsa
openssl-easyrsa.cnf
vars
x509-types

root@vpn:~/easy-rsa# ./easyrsa init-pki
Using Easy-RSA 'vars' configuration:
* /root/easy-rsa/vars

Notice
------
'init-pki' complete; you may now create a CA or requests.

Your newly created PKI dir is:
* /root/easy-rsa/pki

Using Easy-RSA configuration:
* /root/easy-rsa/vars

root@vpn:~/easy-rsa# ./easyrsa --batch --req-cn="TTR Lab VPN CA" build-ca nopass
Using Easy-RSA 'vars' configuration:
* /root/easy-rsa/vars
[... 2 lines trimmed: key generation progress ...]

Notice
------
CA creation complete. Your new CA certificate is at:
* /root/easy-rsa/pki/ca.crt

Create an OpenVPN TLS-AUTH|TLS-CRYPT-V1 key now: See 'help gen-tls'

Build-ca completed successfully.


root@vpn:~/easy-rsa# ./easyrsa --batch build-server-full server nopass
Using Easy-RSA 'vars' configuration:
* /root/easy-rsa/vars
[... 2 lines trimmed: key generation progress ...]
-----

Notice
------
Private-Key and Public-Certificate-Request files created.
Your files are:
* req: /root/easy-rsa/pki/reqs/server.req
* key: /root/easy-rsa/pki/private/server.key

Using configuration from /root/easy-rsa/pki/5c863e2b/temp.6.1
Check that the request matches the signature
Signature ok
The Subject's Distinguished Name is as follows
commonName            :ASN.1 12:'server'
Certificate is to be certified until Jan 23 05:17:34 2029 GMT (825 days)

Write out database with 1 new entries
Database updated

Notice
------
Inline file created:
* /root/easy-rsa/pki/inline/private/server.inline


Notice
------
Certificate created at:
* /root/easy-rsa/pki/issued/server.crt


root@vpn:~/easy-rsa# for u in alice bob branch; do ./easyrsa --batch build-client-full $u nopass; done
Using Easy-RSA 'vars' configuration:
* /root/easy-rsa/vars
[... 2 lines trimmed: key generation progress ...]
-----

Notice
------
Private-Key and Public-Certificate-Request files created.
Your files are:
* req: /root/easy-rsa/pki/reqs/alice.req
* key: /root/easy-rsa/pki/private/alice.key

Using configuration from /root/easy-rsa/pki/1264e4b7/temp.6.1
Check that the request matches the signature
Signature ok
The Subject's Distinguished Name is as follows
commonName            :ASN.1 12:'alice'
Certificate is to be certified until Jan 23 05:17:34 2029 GMT (825 days)

Write out database with 1 new entries
Database updated

Notice
------
Inline file created:
* /root/easy-rsa/pki/inline/private/alice.inline


Notice
------
Certificate created at:
* /root/easy-rsa/pki/issued/alice.crt

[... 67 lines trimmed: the same output for bob and branch ...]

root@vpn:~/easy-rsa# ./easyrsa gen-crl
Using Easy-RSA 'vars' configuration:
* /root/easy-rsa/vars
Using configuration from /root/easy-rsa/openssl-easyrsa.cnf

Notice
------
An updated CRL DER copy has been created:
* /root/easy-rsa/pki/crl.der

An updated CRL has been created:
* /root/easy-rsa/pki/crl.pem

IMPORTANT: When the CRL expires, an OpenVPN Server which uses a
CRL will reject ALL new connections, until the CRL is replaced.


root@vpn:~/easy-rsa# ls pki pki/issued pki/private
pki:
ca.crt
certs_by_serial
crl.der
crl.pem
index.txt
index.txt.attr
index.txt.attr.old
index.txt.old
inline
issued
private
reqs
revoked
serial
serial.old
vars.example

pki/issued:
alice.crt
bob.crt
branch.crt
server.crt

pki/private:
alice.key
bob.key
branch.key
ca.key
server.key
  • Lines 1–5: A private copy of easy-rsa in root's home, with its own vars settings file.
  • Lines 21–33: The CA: ca.crt (public, given to everyone) and ca.key (secret, signs everything). The lab skips the passphrase; a real CA shouldn't.
  • Lines 36–68: The server's key and certificate, signed by the CA. Valid for 825 days, easy-rsa's default.
  • Lines 71–105: One certificate per user. Each can be revoked on its own later.
  • Lines 107–121: The certificate revocation list, empty for now. Note easy-rsa's warning about it expiring.
  • Lines 143–154: What you end up with. Everything in private/ stays secret; ca.key most of all.

Check your understanding

Why give every user their own certificate, instead of one shared certificate for the whole team?

  • So one person can be removed by revoking their certificate, without reissuing everyone else's.
  • Because OpenVPN refuses two connections with the same certificate.
  • Shared certificates are slower.
  • To avoid needing a CA.