Running Your Own Root CA for the Homelab

What started as a GitHub README turned into a proper blog post

Posted by Rene Welches on Wednesday, February 18, 2026
Last Modified on Thursday, February 19, 2026

It Started as a GitHub README

When I first set up a custom Root CA for my homelab I figured it didn’t warrant a full blog post. I threw the steps into a GitHub repo — homelab-self-signed-cert-setup — and called it done.

Then the macOS Keychain bit me, and I spent longer debugging a git push failure than I care to admit. That’s what turned this into a blog post.

Why Bother With a Root CA?

Once your homelab grows beyond a couple of services, you start running things under internal domain names — Proxmox, Forgejo, Home Assistant, Grafana, and so on. Browsers and tools complain about self-signed certs. Instead of clicking through warnings forever, you can create your own Certificate Authority, trust it once on each machine, and sign as many internal certs as you want.

Step 1: Install OpenSSL (macOS)

The version of OpenSSL bundled with macOS is actually LibreSSL, which works for most things but can behave differently. Install the real thing via Homebrew:

brew install openssl

Step 2: Generate the CA Private Key

openssl genrsa -aes256 -out homelab-ca-private_key.pem 2048

This creates a 2048-bit RSA private key encrypted with AES-256. You’ll be prompted for a passphrase — use a strong one and store it somewhere safe (a password manager). Every time you sign a new certificate you’ll need it.

Flags:

  • -aes256 — encrypts the key with your passphrase
  • 2048 — key size in bits (adequate for homelab use)

Step 3: Create the Self-Signed Root CA Certificate

openssl req -x509 -new -nodes -key homelab-ca-private_key.pem \
  -sha256 -days 3650 -out homelab-root-CA.crt -subj "/CN=Home Lab CA"

This produces homelab-root-CA.crt, valid for 10 years. This is the file you’ll distribute to every machine that needs to trust your internal certificates.

Step 4: Sign a Server Certificate

Here’s the workflow for signing a certificate for a specific service — I’ll use Proxmox as the example.

4a. Generate a private key on the server

openssl genrsa -out proxmox.key 2048

4b. Create a config file with Subject Alternative Names

Modern TLS requires SANs — a bare CN is no longer sufficient. Create proxmox.cnf:

[req]
default_bits = 2048
prompt = no
default_md = sha256
distinguished_name = distinguished_name

[distinguished_name]
C = US
ST = New York
L = New York
O = home lab
OU = Proxmox
CN = proxmox.homelab.home, 192.168.1.10

[v3_req]
keyUsage = critical, digitalSignature, keyEncipherment
extendedKeyUsage = serverAuth
subjectAltName = @alt_names

[alt_names]
DNS.1 = proxmox.homelab.home
IP.1 = 192.168.1.10

Adjust the DNS and IP entries to match your environment.

4c. Generate the Certificate Signing Request

openssl req -new -key proxmox.key -out proxmox.csr -config proxmox.cnf

4d. Copy the CSR to the machine holding your CA keys

scp proxmox.csr proxmox.cnf your-ca-machine:~/

Keep proxmox.key on the Proxmox server — it should never leave.

4e. Sign the CSR with your Root CA

openssl x509 -req -in proxmox.csr -CA homelab-root-CA.crt \
  -CAkey homelab-ca-private_key.pem \
  -CAcreateserial -out proxmox.crt -days 365 -sha256 \
  -extfile proxmox.cnf -extensions v3_req

4f. Verify the SANs are present

openssl x509 -in proxmox.crt -text -noout | grep "Subject Alternative Name" -A 1

Copy the resulting proxmox.crt back to the Proxmox node. You can upload it via the Proxmox web UI under Node → Certificates → Upload Custom Certificate.

Step 5: Trust the Root CA

Linux (Debian/Ubuntu)

sudo cp homelab-root-CA.crt /usr/local/share/ca-certificates/
sudo update-ca-certificates --fresh

This is also needed if your Debian cloud-init VMs need to pull from internal services — I mentioned this in my Proxmox cloud image template post.

macOS — and Where It Gets Tricky

sudo security add-trusted-cert -d -r trustRoot \
    -k /Library/Keychains/System.keychain \
    /Users/rene/Documents/Workspace/homelab-certificates/homelab-root-CA.crt

After running this, Keychain Access shows the certificate with “Always Trust” on every entry. Safari and Chrome pick it up correctly.

But git push to my internal Forgejo instance kept failing with a certificate verification error. The Keychain said it was trusted. Git disagreed.

The macOS Keychain + Git Problem

It turns out Git on macOS does not use the system Keychain for TLS verification by default — it uses its own bundled CA bundle (from the curl or OpenSSL it was compiled against). The Keychain trust setting is irrelevant to it.

The fix is to tell Git explicitly where to find your root CA for requests to that specific host:

git config --global http.https://forgejo.grumples.home.sslCAInfo \
    /Users/rene/Documents/Workspace/homelab-certificates/homelab-root-CA.crt

This adds a scoped entry to your ~/.gitconfig that applies only to that host:

[http "https://forgejo.grumples.home"]
    sslCAInfo = /Users/rene/Documents/Workspace/homelab-certificates/homelab-root-CA.crt

After that, git push, git pull, and git clone all work without any certificate errors.

If you have multiple internal services using the same CA, add a line for each hostname. The scoped format keeps things tidy and avoids globally disabling certificate verification (which you should never do).

Recap

StepCommand / Tool
Generate CA keyopenssl genrsa -aes256
Create Root CA certopenssl req -x509
Sign a server certopenssl x509 -req
Trust on Linuxupdate-ca-certificates
Trust on macOS (system)security add-trusted-cert
Trust in Git (macOS)git config --global http.<url>.sslCAInfo

The full setup scripts live in the homelab-self-signed-cert-setup repo if you want a quick reference without the commentary.