Build a local certificate authority
Create a certificate signing request
Generate a server key and CSR containing the identity and public key to be signed.
10 minute lesson
A server never sends its private key to a certificate authority. Instead it sends a certificate signing request (CSR). The CSR carries a public key, requested identity information, and a signature proving possession of the private key. The CA reads the request, decides whether the identity is allowed, and returns a signed certificate.
This split is what makes public CAs possible: Let’s Encrypt signs millions of certificates without ever seeing a private key.
Create a key and CSR for app.lab.test in one command:
openssl req -new -newkey rsa:2048 -nodes -keyout app.key -out app.csr -subj '/CN=app.lab.test' -addext 'subjectAltName=DNS:app.lab.test,DNS:localhost'
A few options worth understanding. -newkey rsa:2048 generates a fresh 2048-bit RSA key alongside the request. -nodes leaves the server key unencrypted, so the lab server can start without a passphrase prompt — acceptable here because the file stays on your machine with tight permissions. -addext puts both hostnames into the subjectAltName request, which is where clients will actually look for names.
Inspect what you are about to hand to the CA:
openssl req -in app.csr -noout -text -verify
The -verify flag checks the CSR’s self-signature and prints a verify confirmation line before the decode. In the text output, confirm two things: the Subject shows CN = app.lab.test, and the Requested Extensions section lists both DNS names:
Requested Extensions:
X509v3 Subject Alternative Name:
DNS:app.lab.test, DNS:localhost
Confirm both requested names and the signature before signing anything.
A common mistake is skipping -addext and requesting only a common name. Some signing setups will not add a SAN for you, and a certificate without SAN entries fails name verification in modern clients even though every field looks reasonable. Catch this at the CSR stage, where fixing it costs one command.
Remember which file is which. The CSR is shareable with the signer — it contains only public information. The generated app.key is not. If you ever paste a CSR into a support ticket, double-check you did not paste the key by mistake.
Lesson completed