# OpenVPN PKI — offline CA workflow The CA private key **never touches the VPS**. Run easy-rsa on an offline machine (or at minimum a machine that isn't this server), then copy only the issued material here. ## One-time CA + server cert (on the offline machine) ```bash git clone https://github.com/OpenVPN/easy-rsa.git && cd easy-rsa/easyrsa3 ./easyrsa init-pki ./easyrsa build-ca # sets the CA passphrase — keep offline ./easyrsa build-server-full racknerd-vpn nopass openvpn --genkey tls-crypt ta.key # shared tls-crypt key ./easyrsa gen-crl ``` ## Copy to the VPS (this directory) | File on offline box | Name here | |--------------------------------------|---------------| | `pki/ca.crt` | `ca.crt` | | `pki/issued/racknerd-vpn.crt` | `server.crt` | | `pki/private/racknerd-vpn.key` | `server.key` | | `ta.key` | `ta.key` | | `pki/crl.pem` (optional, see server.conf) | `crl.pem` | `chmod 600 server.key ta.key` after copying. ## Per-user client certs (offline) ```bash ./easyrsa build-client-full nick nopass ``` Build the client's `.ovpn` from `client/client.ovpn.template`, pasting `ca.crt`, the client cert/key, and `ta.key` into the inline blocks. CN should match the AD username — the server logs use it (`username-as-common-name` keeps them consistent). ## Revoking a client ```bash ./easyrsa revoke nick && ./easyrsa gen-crl ``` Copy the fresh `crl.pem` here, uncomment `crl-verify` in `server.conf`, and `docker compose restart openvpn`. Everything in this directory except this README is gitignored.