The most surprising thing about running your own Certificate Authority (CA) is how little the "certificate" part matters to the system; it’s all about the trust.

Let’s see this in action. We’re going to generate a private CA, then use it to sign a certificate for a hypothetical web server.

First, we need a private key for our CA. This is the crown jewel, the thing that grants us authority.

openssl genpkey -algorithm RSA -out ca.key -aes256

This creates ca.key, a strong RSA private key protected by AES-256 encryption. You’ll be prompted for a passphrase. Remember it; you’ll need it every time you use this key.

Next, we need a self-signed certificate for our CA. This certificate is the CA in the eyes of anything that trusts it.

openssl req -new -x509 -days 3650 -key ca.key -out ca.crt -sha256 -subj "/CN=My Private CA/O=My Org/C=US"

ca.crt is now our CA’s public certificate. It’s valid for 10 years (-days 3650). The -subj flag sets the distinguished name (DN) of the CA. The CN (Common Name) is crucial here.

Now, let’s pretend we have a web server that needs a certificate. First, it needs its own private key and a Certificate Signing Request (CSR).

openssl genpkey -algorithm RSA -out server.key
openssl req -new -key server.key -out server.csr -sha256 -subj "/CN=my.internal.server.com/O=My Org/C=US"

server.key is the server’s secret. server.csr is the public request, containing the server’s public key and its DN. The CN here must match the hostname the server will be accessed by.

With the CSR in hand, we can now use our CA to sign it. This is the act of granting trust.

openssl x509 -req -days 365 -in server.csr -CA ca.crt -CAkey ca.key -CAcreateserial -out server.crt -sha256 -extfile <(printf "subjectAltName=DNS:my.internal.server.com,DNS:www.my.internal.server.com")

This command is the core of it.

  • -in server.csr: The request we’re signing.
  • -CA ca.crt -CAkey ca.key: Specifies our CA’s certificate and private key. You’ll be prompted for the CA key’s passphrase.
  • -CAcreateserial: Creates ca.srl, a file that keeps track of the serial numbers of certificates issued by this CA. This prevents issuing certificates with duplicate serial numbers.
  • -out server.crt: The final, signed certificate for the server.
  • -extfile <(printf "subjectAltName=DNS:my.internal.server.com,DNS:www.my.internal.server.com"): This is critical. It adds Subject Alternative Names (SANs) to the certificate. Modern browsers and clients rely heavily on SANs, often ignoring the CN. Without this, your certificate might not work for my.internal.server.com if the browser checks SANs.

The server.crt is what your web server will present. The server.key is what it uses to encrypt. Crucially, any client connecting to this server needs to trust ca.crt. This means distributing ca.crt to the client’s trust store.

Think of the CA certificate (ca.crt) as a root of trust. When a client receives a certificate signed by that CA, it checks if it already trusts that root. If it does, it implicitly trusts the signed certificate. This is why you can’t just issue certificates for public websites; everyone would need to trust your private CA first. For internal services, you can manage this trust distribution.

The real power of a CA isn’t in the cryptographic strength of the certificates themselves, but in the process of establishing and distributing trust. A certificate is just a signed statement of identity and public key; the CA’s signature is what validates that statement.

The next step is to configure your web server (e.g., Nginx or Apache) to use server.crt and server.key, and then to configure your clients to trust ca.crt.

Want structured learning?

Take the full Tls-ssl course →