# Create a private root certificate authority

To create a root CA, generate a key and a self-signed CA certificate with the CA basic constraint set — `openssl req -x509 -new -newkey rsa:4096 -keyout ca.key -out ca.crt -days 3650 -subj "/CN=Example Internal Root CA" -addext "basicConstraints=critical,CA:TRUE" -addext "keyUsage=critical,keyCertSign,cRLSign"`. The `basicConstraints=CA:TRUE` extension is what makes it a CA rather than an ordinary self-signed certificate; without it nothing will accept certificates it signs. Encrypt the CA key with a passphrase, because anything holding it can issue certificates your machines will trust.

Source: https://certguru.io/openssl/create-root-ca/
Last updated: 2026-08-19
Commands verified against OpenSSL 3.5.7.

---

## Step 1 — the CA private key

Encrypt it. This is the one key where a passphrase is unambiguously correct, because a CA key is not
read by an unattended service:

*4096-bit RSA, encrypted*

```bash
openssl genpkey -algorithm RSA -pkeyopt rsa_keygen_bits:4096 -aes-256-cbc -out ca.key
```

```bash
chmod 400 ca.key
```

## Step 2 — the self-signed CA certificate

*A root CA certificate valid for ten years*

```bash
openssl req -x509 -new -key ca.key -out ca.crt -days 3650 -sha256 \
  -subj "/C=US/O=Example Inc/CN=Example Inc Internal Root CA" \
  -addext "basicConstraints=critical,CA:TRUE" \
  -addext "keyUsage=critical,keyCertSign,cRLSign" \
  -addext "subjectKeyIdentifier=hash"
```

| Placeholder | What to put there |
| --- | --- |
| `basicConstraints=critical,CA:TRUE` | What makes this a CA. Marked critical so it cannot be ignored. |
| `keyUsage=critical,keyCertSign,cRLSign` | Restricts the key to signing certificates and revocation lists. |
| `subjectKeyIdentifier=hash` | Lets clients link issued certificates back to this CA reliably. |
| `-days 3650` | Ten years. Longer means fewer trust-store updates and a longer-lived risk. |

> **This key can impersonate anything**
>
> Anyone holding `ca.key` and its passphrase can issue a certificate for any hostname — your bank,
>   your identity provider, anything — and every machine that trusts your root will accept it. Keep it
>   offline, encrypted, and off any machine that faces the internet.

## Step 3 — check what you built

```bash
openssl x509 -in ca.crt -noout -subject -issuer -dates -ext basicConstraints -ext keyUsage
```

Expected output:

```
subject=C = US, O = Example Inc, CN = Example Inc Internal Root CA
issuer=C = US, O = Example Inc, CN = Example Inc Internal Root CA
notBefore=Aug 19 12:00:00 2026 GMT
notAfter=Aug 17 12:00:00 2036 GMT
X509v3 Basic Constraints: critical
    CA:TRUE
X509v3 Key Usage: critical
    Certificate Sign, CRL Sign
```

Identical subject and issuer confirms it is self-signed — correct for a root. `CA:TRUE` confirms it
can sign. If `CA:TRUE` is missing, start again; certificates signed by this will be rejected and the
error will not obviously point back here.

## Step 4 — distribute the CA certificate

Install `ca.crt` — never `ca.key` — on every machine that needs to trust what you issue:

#### Debian / Ubuntu

```bash
sudo cp ca.crt /usr/local/share/ca-certificates/example-internal-ca.crt
sudo update-ca-certificates
```

#### RHEL / Fedora

```bash
sudo cp ca.crt /etc/pki/ca-trust/source/anchors/
sudo update-ca-trust extract
```

#### macOS

```bash
sudo security add-trusted-cert -d -r trustRoot \
  -k /Library/Keychains/System.keychain ca.crt
```

#### Alpine

```bash
sudo apk add ca-certificates
sudo cp ca.crt /usr/local/share/ca-certificates/
sudo update-ca-certificates
```

## Step 5 — issue your first certificate

*Generate a key and CSR for a server*

```bash
openssl req -new -newkey rsa:2048 -nodes \
  -keyout server.key -out server.csr \
  -subj "/CN=service.internal" \
  -addext "subjectAltName=DNS:service.internal,DNS:*.service.internal"
```

*Sign it with the CA*

```bash
openssl x509 -req -in server.csr -CA ca.crt -CAkey ca.key -CAcreateserial \
  -out server.crt -days 397 -sha256 \
  -copy_extensions copyall
```

> **-copy_extensions is required for SANs**
>
> Without it, `openssl x509 -req` silently drops every extension from the CSR, including the subject
>   alternative names — producing a certificate that browsers reject. See
>   [signing a CSR with your CA](/openssl/sign-csr-with-ca/) for the safer config-file approach and
>   why `copyall` deserves care.

## Why a CA beats self-signed certificates

| | Self-signed | Private CA |
| --- | --- | --- |
| Trust-store operations | One per certificate, per machine | One per machine, ever |
| Renewals | Re-trust every time | Just reissue |
| Revocation | None | Possible via CRL |
| Effort for 1 certificate | Lower | Higher |
| Effort for 5+ certificates | Much higher | Much lower |


## Frequently asked questions

### What makes a certificate a CA certificate?

The `basicConstraints` extension containing `CA:TRUE`, marked critical. Without it, a certificate is an ordinary end-entity certificate and every correct implementation will refuse to accept signatures it makes on other certificates.

### How long should a root CA last?

Ten years is typical for an internal root, because replacing it means touching the trust store on every machine again. The trade-off is that a long-lived root is a long-lived liability if the key is ever exposed.

### Should I sign certificates directly with the root?

For a small internal setup it is acceptable and much simpler. The reason public CAs do not is that the root key can then stay offline — an intermediate does the day-to-day signing, and a compromised intermediate can be revoked without reissuing every trust store.

### Where should the CA key live?

Somewhere offline, encrypted, and backed up separately from anything internet-facing. Anyone with that key and its passphrase can issue certificates that every machine trusting your root will accept, for any hostname including ones you do not own.


## References

- [openssl-req(1)](https://docs.openssl.org/3.5/man1/openssl-req/) — creating the self-signed root
- [CA/Browser Forum Baseline Requirements](https://cabforum.org/working-groups/server/baseline-requirements/documents/) — what a publicly trusted CA is permitted to issue

## Related pages

- https://certguru.io/openssl/sign-csr-with-ca/
- https://certguru.io/openssl/create-intermediate-ca/
- https://certguru.io/concepts/root-vs-intermediate-ca/
- https://certguru.io/openssl/generate-self-signed-certificate/
- https://certguru.io/concepts/certificate-chain/

--
CertGuru — https://certguru.io
