Self-Signed CA Certificates: Be Your Own Certificate Authority

Or: How to Stop Paying for SSL Certs in Your Homelab

You’re setting up a new service in your homelab. Maybe it’s Proxmox, maybe it’s your private Git server, maybe it’s that sketchy Docker container you found on GitHub. Either way, you need HTTPS, and you’re tired of clicking through “Your connection is not private” warnings like it’s 2005.

The solution? Become your own Certificate Authority. It’s easier than it sounds, and by the end of this guide, your browser will trust your self-signed certificates like they came from DigiCert themselves.


The Big Picture: How Certificate Trust Works

A brief detour into PKI land

Before we dive into commands, let’s understand what we’re building:

┌─────────────────────────────────────────────────────────────────┐
│                    Your Private CA                              │
│                  (The Root of Trust)                            │
│                         │                                       │
│                         ▼                                       │
│              ┌─────────────────────┐                            │
│              │   CA Certificate    │  ← Install this on devices │
│              │   (ca.crt)          │                            │
│              └─────────────────────┘                            │
│                         │                                       │
│                    Signs ▼                                      │
│         ┌───────────────┴───────────────┐                       │
│         ▼                               ▼                       │
│  ┌─────────────┐                 ┌─────────────┐                │
│  │ Server Cert │                 │ Client Cert │                │
│  │ (web, mail) │                 │ (mTLS auth) │                │
│  └─────────────┘                 └─────────────┘                │
└─────────────────────────────────────────────────────────────────┘

The trust chain:

  1. You create a CA (Certificate Authority) with its own key pair
  2. You install the CA certificate on all devices that should trust it
  3. You use the CA to sign server/client certificates
  4. Devices see a certificate signed by your CA → “I trust this CA” → Connection trusted

Part 1: Creating Your Certificate Authority

With great power comes great responsibility

Step 1: Generate the CA Private Key

1. Create a directory for your CA
mkdir -p ~/myca/{certs,private,newcerts}
cd ~/myca

1. Generate a 4096-bit RSA private key for the CA
openssl genrsa -aes256 -out private/ca.key 4096

You’ll be prompted for a passphrase. Use a strong one and don’t lose it. This key is the crown jewel – anyone with access to it can sign certificates that your devices will trust.

Pro tip: Store this key offline or in a password manager. You only need it when signing new certificates.

Step 2: Create the CA Certificate

1. Generate the CA certificate (valid for 10 years)
openssl req -new -x509 -days 3650 -key private/ca.key -sha256 -out certs/ca.crt

You’ll be prompted for certificate details:

Country Name (2 letter code) [AU]: DE
State or Province Name []: NRW
Locality Name []: Dusseldorf
Organization Name []: Homelab CA
Organizational Unit Name []: IT Department
Common Name []: Homelab Root CA
Email Address []: admin@homelab.local

Fun fact: The Common Name (CN) is what shows up in certificate viewers. Make it descriptive so you recognize it later.

Step 3: Verify Your CA Certificate

1. View the certificate details
openssl x509 -in certs/ca.crt -text -noout

Look for:

  • Issuer and Subject should be identical (it’s self-signed)
  • CA:TRUE in the Basic Constraints
  • Validity dates that make sense

Part 2: Creating Server Certificates

For your HTTPS-enabled services

Step 1: Generate a Private Key for the Server

1. Generate server private key (no passphrase for automated services)
openssl genrsa -out server.key 2048

Step 2: Create a Certificate Signing Request (CSR)

1. Generate CSR
openssl req -new -key server.key -out server.csr

Fill in the details. The Common Name should match your server’s hostname (e.g., gitea.homelab.local).

Step 3: Create a Config File for SANs

Modern browsers require Subject Alternative Names (SANs). Create a file called server.ext:

authorityKeyIdentifier=keyid,issuer
basicConstraints=CA:FALSE
keyUsage = digitalSignature, nonRepudiation, keyEncipherment, dataEncipherment
subjectAltName = @alt_names

[alt_names]
DNS.1 = gitea.homelab.local
DNS.2 = gitea
DNS.3 = *.homelab.local
IP.1 = 192.168.1.100
IP.2 = 127.0.0.1

Step 4: Sign the Certificate with Your CA

1. Sign the server certificate (valid for 1 year)
openssl x509 -req -in server.csr \
    -CA ~/myca/certs/ca.crt \
    -CAkey ~/myca/private/ca.key \
    -CAcreateserial \
    -out server.crt \
    -days 365 \
    -sha256 \
    -extfile server.ext

Step 5: Verify the Server Certificate

1. Verify the certificate chain
openssl verify -CAfile ~/myca/certs/ca.crt server.crt

Should output: server.crt: OK


Part 3: Creating Client Certificates

For mutual TLS (mTLS) authentication

Client certificates let you authenticate users/devices instead of (or in addition to) passwords. Perfect for:

  • VPN authentication
  • API access control
  • Zero-trust architectures
  • Making your security team happy

Step 1: Generate Client Private Key

1. Generate client key
openssl genrsa -out client.key 2048

Step 2: Create Client CSR

openssl req -new -key client.key -out client.csr

For client certs, the Common Name typically identifies the user or device (e.g., john.doe@company.com or laptop-001).

Step 3: Create Client Extension File

Create client.ext:

authorityKeyIdentifier=keyid,issuer
basicConstraints=CA:FALSE
keyUsage = digitalSignature, keyEncipherment
extendedKeyUsage = clientAuth
subjectAltName = @alt_names

[alt_names]
email = john.doe@company.com

Step 4: Sign the Client Certificate

openssl x509 -req -in client.csr \
    -CA ~/myca/certs/ca.crt \
    -CAkey ~/myca/private/ca.key \
    -CAcreateserial \
    -out client.crt \
    -days 365 \
    -sha256 \
    -extfile client.ext

Step 5: Create PKCS#12 Bundle (for browsers/devices)

Most devices import client certificates as .p12 or .pfx files:

1. Bundle key + cert + CA into a .p12 file
openssl pkcs12 -export \
    -out client.p12 \
    -inkey client.key \
    -in client.crt \
    -certfile ~/myca/certs/ca.crt

You’ll set an export password. The user needs this to import the certificate.


Part 4: Trusting Your CA on Different Platforms

The “make the warnings go away” section

Now comes the fun part: making every device trust your CA.


macOS: Adding CA to System Keychain

Method 1: GUI (Keychain Access)

  1. Double-click ca.crt to open Keychain Access
  2. Select “System” keychain (not “login” – we want system-wide trust)
  3. Find your certificate, double-click it
  4. Expand “Trust” section
  5. Set “When using this certificate” to Always Trust
  6. Close and enter your password

Method 2: Command Line

1. Add CA to System keychain and trust it
sudo security add-trusted-cert -d -r trustRoot \
    -k /Library/Keychains/System.keychain ca.crt

Verify it worked:

security find-certificate -a -c "Homelab Root CA" /Library/Keychains/System.keychain

To remove later:

sudo security delete-certificate -c "Homelab Root CA" /Library/Keychains/System.keychain

Windows: Adding CA to Certificate Store

Method 1: GUI (Certificate Manager)

  1. Double-click ca.crt
  2. Click “Install Certificate…”
  3. Select “Local Machine” (requires admin)
  4. Choose “Place all certificates in the following store”
  5. Click “Browse” and select Trusted Root Certification Authorities
  6. Finish the wizard

Method 2: PowerShell (Admin)

1. Import CA certificate to Trusted Root store
Import-Certificate -FilePath "C:\path\to\ca.crt" `
    -CertStoreLocation Cert:\LocalMachine\Root

Method 3: certutil

certutil -addstore -f "Root" ca.crt

Verify it worked:

Get-ChildItem Cert:\LocalMachine\Root | Where-Object {$_.Subject -like "*Homelab*"}

To remove later:

1. Find the thumbprint first
Get-ChildItem Cert:\LocalMachine\Root | Where-Object {$_.Subject -like "*Homelab*"}

1. Remove by thumbprint
Remove-Item Cert:\LocalMachine\Root\[THUMBPRINT]

Linux: Adding CA to System Trust Store

Linux varies by distribution. Here are the major ones:

Debian/Ubuntu:

1. Copy CA cert to the trusted directory
sudo cp ca.crt /usr/local/share/ca-certificates/homelab-ca.crt

1. Update the CA store
sudo update-ca-certificates

RHEL/CentOS/Fedora:

1. Copy CA cert
sudo cp ca.crt /etc/pki/ca-trust/source/anchors/homelab-ca.crt

1. Update the CA store
sudo update-ca-trust

Arch Linux:

1. Copy CA cert
sudo cp ca.crt /etc/ca-certificates/trust-source/anchors/homelab-ca.crt

1. Update the CA store
sudo trust extract-compat

Verify it worked:

1. Test with curl
curl https://your-server.homelab.local

1. Or check the trust store
trust list | grep -i homelab

To remove later:

1. Debian/Ubuntu
sudo rm /usr/local/share/ca-certificates/homelab-ca.crt
sudo update-ca-certificates --fresh

1. RHEL/CentOS/Fedora
sudo rm /etc/pki/ca-trust/source/anchors/homelab-ca.crt
sudo update-ca-trust

Android: Adding CA to User/System Trust

Method 1: User Trust Store (No Root Required)

  1. Copy ca.crt to your device (email, cloud, USB)
  2. Go to Settings → Security → Encryption & credentials
  3. Tap Install a certificate → CA certificate
  4. Select your ca.crt file
  5. Confirm the security warning

Important: User-installed CAs show a persistent “Network may be monitored” warning. Apps can also choose to ignore user CAs (Android 7+).

Method 2: System Trust Store (Root Required)

1. On a rooted Android device or emulator

1. Convert to Android format (hash-named)
HASH=$(openssl x509 -inform PEM -subject_hash_old -in ca.crt | head -1)
cp ca.crt ${HASH}.0

1. Push to device
adb root
adb remount
adb push ${HASH}.0 /system/etc/security/cacerts/
adb shell chmod 644 /system/etc/security/cacerts/${HASH}.0
adb reboot

For Android 14+ (read-only /system):

1. Mount system as writable (Magisk or similar required)
adb shell
su
mount -o rw,remount /system
1. Then copy the certificate as above

iOS/iPadOS: Adding CA via Profile

iOS requires certificates to be installed via a configuration profile.

Method 1: Direct Installation

  1. Email the ca.crt to yourself or host it on a web server
  2. Open the certificate on your iOS device
  3. Go to Settings → General → VPN & Device Management
  4. You’ll see your certificate under “Downloaded Profile”
  5. Tap it and select Install
  6. Important: Go to Settings → General → About → Certificate Trust Settings
  7. Enable full trust for your root certificate

Method 2: Apple Configurator / MDM

For enterprise deployment, create a .mobileconfig profile:

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>

<key>PayloadContent</key>

<array>

<dict>

<key>PayloadCertificateFileName</key>

<string>homelab-ca.crt</string>

<key>PayloadContent</key>

<data>
            [BASE64-ENCODED-CERTIFICATE-HERE]
            </data>

<key>PayloadDescription</key>

<string>Adds Homelab Root CA</string>

<key>PayloadDisplayName</key>

<string>Homelab Root CA</string>

<key>PayloadIdentifier</key>

<string>com.homelab.ca</string>

<key>PayloadType</key>

<string>com.apple.security.root</string>

<key>PayloadUUID</key>

<string>A1B2C3D4-E5F6-7890-ABCD-EF1234567890</string>

<key>PayloadVersion</key>

<integer>1</integer>
        </dict>
    </array>

<key>PayloadDisplayName</key>

<string>Homelab CA Profile</string>

<key>PayloadIdentifier</key>

<string>com.homelab.ca.profile</string>

<key>PayloadRemovalDisallowed</key>
    <false/>

<key>PayloadType</key>

<string>Configuration</string>

<key>PayloadUUID</key>

<string>12345678-90AB-CDEF-1234-567890ABCDEF</string>

<key>PayloadVersion</key>

<integer>1</integer>
</dict>
</plist>

Generate the base64 content:

base64 -i ca.crt

To remove later: Settings → General → VPN & Device Management → Select profile → Remove Profile


Bonus: Certificate Generator Script

Because automation is the DevOps way

Save this script as generate-cert.sh and never type those OpenSSL commands again:

#!/bin/bash
1. 
1. Certificate Generator Script
1. Creates CA, server, and client certificates with minimal effort
1. 
1. Usage:
1.   ./generate-cert.sh ca                     # Create new CA
1.   ./generate-cert.sh server 
<hostname>      # Create server cert
1.   ./generate-cert.sh client 
<name>          # Create client cert
1. 

set -e

1. Configuration
CA_DIR="${CA_DIR:-$HOME/myca}"
CA_KEY="$CA_DIR/private/ca.key"
CA_CERT="$CA_DIR/certs/ca.crt"
DAYS_CA=3650
DAYS_CERT=365
KEY_SIZE_CA=4096
KEY_SIZE_CERT=2048

1. Colors for output
RED='\033[0;31m'
GREEN='\033[0;32m'
YELLOW='\033[1;33m'
NC='\033[0m' # No Color

log_info() { echo -e "${GREEN}[INFO]${NC} $1"; }
log_warn() { echo -e "${YELLOW}[WARN]${NC} $1"; }
log_error() { echo -e "${RED}[ERROR]${NC} $1"; exit 1; }

1. Create CA directory structure
init_ca_dir() {
    mkdir -p "$CA_DIR"/{certs,private,newcerts}
    chmod 700 "$CA_DIR/private"
    touch "$CA_DIR/index.txt"
    [ -f "$CA_DIR/serial" ] || echo 1000 > "$CA_DIR/serial"
}

1. Generate new Certificate Authority
generate_ca() {
    log_info "Creating new Certificate Authority..."
    init_ca_dir

    if [ -f "$CA_KEY" ]; then
        log_warn "CA already exists at $CA_DIR"
        read -p "Overwrite? (y/N) " -n 1 -r
        echo
        [[ ! $REPLY =~ ^[Yy]$ ]] && exit 0
    fi

    1. Generate CA private key
    log_info "Generating CA private key (you will be prompted for a passphrase)..."
    openssl genrsa -aes256 -out "$CA_KEY" $KEY_SIZE_CA
    chmod 400 "$CA_KEY"

    1. Generate CA certificate
    log_info "Generating CA certificate..."
    openssl req -new -x509 -days $DAYS_CA \
        -key "$CA_KEY" \
        -sha256 \
        -out "$CA_CERT" \
        -subj "/CN=Homelab Root CA/O=Homelab/C=DE"

    log_info "CA created successfully!"
    log_info "CA Certificate: $CA_CERT"
    log_info "CA Private Key: $CA_KEY"
    echo
    log_warn "IMPORTANT: Back up $CA_KEY securely and remember your passphrase!"
}

1. Generate server certificate
generate_server() {
    local hostname="$1"
    [ -z "$hostname" ] && log_error "Usage: $0 server 
<hostname>"

    1. Check CA exists
    [ ! -f "$CA_KEY" ] || [ ! -f "$CA_CERT" ] && \
        log_error "CA not found. Run '$0 ca' first."

    local output_dir="./certs/$hostname"
    mkdir -p "$output_dir"

    log_info "Generating server certificate for: $hostname"

    1. Generate private key
    openssl genrsa -out "$output_dir/$hostname.key" $KEY_SIZE_CERT
    chmod 600 "$output_dir/$hostname.key"

    1. Create extension file for SANs
    cat > "$output_dir/$hostname.ext" << EOF
authorityKeyIdentifier=keyid,issuer
basicConstraints=CA:FALSE
keyUsage = digitalSignature, nonRepudiation, keyEncipherment, dataEncipherment
subjectAltName = @alt_names

[alt_names]
DNS.1 = $hostname
DNS.2 = *.$hostname
IP.1 = 127.0.0.1
EOF

    1. Generate CSR
    openssl req -new \
        -key "$output_dir/$hostname.key" \
        -out "$output_dir/$hostname.csr" \
        -subj "/CN=$hostname/O=Homelab/C=DE"

    1. Sign with CA
    log_info "Signing certificate with CA (enter CA passphrase)..."
    openssl x509 -req \
        -in "$output_dir/$hostname.csr" \
        -CA "$CA_CERT" \
        -CAkey "$CA_KEY" \
        -CAcreateserial \
        -out "$output_dir/$hostname.crt" \
        -days $DAYS_CERT \
        -sha256 \
        -extfile "$output_dir/$hostname.ext"

    1. Create fullchain (cert + CA)
    cat "$output_dir/$hostname.crt" "$CA_CERT" > "$output_dir/$hostname.fullchain.crt"

    1. Cleanup CSR and ext file
    rm -f "$output_dir/$hostname.csr" "$output_dir/$hostname.ext"

    log_info "Server certificate created successfully!"
    echo
    echo "Files created in $output_dir/:"
    echo "  - $hostname.key         (Private key)"
    echo "  - $hostname.crt         (Certificate)"
    echo "  - $hostname.fullchain.crt (Certificate + CA chain)"
    echo
    echo "Example nginx config:"
    echo "  ssl_certificate     $output_dir/$hostname.fullchain.crt;"
    echo "  ssl_certificate_key $output_dir/$hostname.key;"
}

1. Generate client certificate
generate_client() {
    local name="$1"
    [ -z "$name" ] && log_error "Usage: $0 client 
<name>"

    1. Check CA exists
    [ ! -f "$CA_KEY" ] || [ ! -f "$CA_CERT" ] && \
        log_error "CA not found. Run '$0 ca' first."

    local output_dir="./certs/clients"
    mkdir -p "$output_dir"

    log_info "Generating client certificate for: $name"

    1. Generate private key
    openssl genrsa -out "$output_dir/$name.key" $KEY_SIZE_CERT
    chmod 600 "$output_dir/$name.key"

    1. Create extension file
    cat > "$output_dir/$name.ext" << EOF
authorityKeyIdentifier=keyid,issuer
basicConstraints=CA:FALSE
keyUsage = digitalSignature, keyEncipherment
extendedKeyUsage = clientAuth
EOF

    1. Generate CSR
    openssl req -new \
        -key "$output_dir/$name.key" \
        -out "$output_dir/$name.csr" \
        -subj "/CN=$name/O=Homelab/C=DE"

    1. Sign with CA
    log_info "Signing certificate with CA (enter CA passphrase)..."
    openssl x509 -req \
        -in "$output_dir/$name.csr" \
        -CA "$CA_CERT" \
        -CAkey "$CA_KEY" \
        -CAcreateserial \
        -out "$output_dir/$name.crt" \
        -days $DAYS_CERT \
        -sha256 \
        -extfile "$output_dir/$name.ext"

    1. Create PKCS#12 bundle
    log_info "Creating PKCS#12 bundle (set an export password)..."
    openssl pkcs12 -export \
        -out "$output_dir/$name.p12" \
        -inkey "$output_dir/$name.key" \
        -in "$output_dir/$name.crt" \
        -certfile "$CA_CERT" \
        -name "$name"

    1. Cleanup
    rm -f "$output_dir/$name.csr" "$output_dir/$name.ext"

    log_info "Client certificate created successfully!"
    echo
    echo "Files created in $output_dir/:"
    echo "  - $name.key   (Private key)"
    echo "  - $name.crt   (Certificate)"
    echo "  - $name.p12   (PKCS#12 bundle for import)"
}

1. Show certificate info
show_info() {
    local cert="$1"
    [ -z "$cert" ] && log_error "Usage: $0 info <certificate.crt>"
    [ ! -f "$cert" ] && log_error "Certificate not found: $cert"

    openssl x509 -in "$cert" -text -noout
}

1. Verify certificate against CA
verify_cert() {
    local cert="$1"
    [ -z "$cert" ] && log_error "Usage: $0 verify <certificate.crt>"
    [ ! -f "$cert" ] && log_error "Certificate not found: $cert"
    [ ! -f "$CA_CERT" ] && log_error "CA certificate not found at $CA_CERT"

    openssl verify -CAfile "$CA_CERT" "$cert"
}

1. Main
case "${1:-}" in
    ca)
        generate_ca
        ;;
    server)
        generate_server "$2"
        ;;
    client)
        generate_client "$2"
        ;;
    info)
        show_info "$2"
        ;;
    verify)
        verify_cert "$2"
        ;;
    *)
        echo "Certificate Generator Script"
        echo
        echo "Usage: $0 
<command> [options]"
        echo
        echo "Commands:"
        echo "  ca                Create new Certificate Authority"
        echo "  server 
<host>     Create server certificate"
        echo "  client 
<name>     Create client certificate"
        echo "  info 
<cert>       Show certificate details"
        echo "  verify 
<cert>     Verify certificate against CA"
        echo
        echo "Environment variables:"
        echo "  CA_DIR            CA directory (default: ~/myca)"
        echo
        echo "Examples:"
        echo "  $0 ca                        # Create CA"
        echo "  $0 server gitea.homelab.local"
        echo "  $0 client john.doe"
        echo "  $0 verify ./certs/server.crt"
        ;;
esac

Usage examples:

1. Make executable
chmod +x generate-cert.sh

1. Create your CA (one-time setup)
./generate-cert.sh ca

1. Generate server certificate
./generate-cert.sh server gitea.homelab.local

1. Generate client certificate (creates .p12 for easy import)
./generate-cert.sh client john.doe

1. Verify a certificate
./generate-cert.sh verify ./certs/gitea.homelab.local/gitea.homelab.local.crt

Quick Reference Card

╔══════════════════════════════════════════════════════════════════╗
║              CERTIFICATE AUTHORITY CHEAT SHEET                   ║
╠══════════════════════════════════════════════════════════════════╣
║ CREATE CA                                                        ║
║   openssl genrsa -aes256 -out ca.key 4096                        ║
║   openssl req -new -x509 -days 3650 -key ca.key -out ca.crt      ║
╠══════════════════════════════════════════════════════════════════╣
║ CREATE SERVER CERT                                               ║
║   openssl genrsa -out server.key 2048                            ║
║   openssl req -new -key server.key -out server.csr               ║
║   openssl x509 -req -in server.csr -CA ca.crt -CAkey ca.key \    ║
║       -CAcreateserial -out server.crt -days 365 -extfile ext     ║
╠══════════════════════════════════════════════════════════════════╣
║ CREATE CLIENT CERT                                               ║
║   openssl genrsa -out client.key 2048                            ║
║   openssl req -new -key client.key -out client.csr               ║
║   openssl x509 -req -in client.csr -CA ca.crt -CAkey ca.key \    ║
║       -CAcreateserial -out client.crt -days 365 -extfile ext     ║
║   openssl pkcs12 -export -out client.p12 -inkey client.key \     ║
║       -in client.crt -certfile ca.crt                            ║
╠══════════════════════════════════════════════════════════════════╣
║ TRUST CA ON SYSTEMS                                              ║
║   macOS:   sudo security add-trusted-cert -d -r trustRoot \      ║
║                -k /Library/Keychains/System.keychain ca.crt      ║
║   Windows: certutil -addstore -f "Root" ca.crt                   ║
║   Ubuntu:  sudo cp ca.crt /usr/local/share/ca-certificates/ \    ║
║                && sudo update-ca-certificates                    ║
║   RHEL:    sudo cp ca.crt /etc/pki/ca-trust/source/anchors/ \    ║
║                && sudo update-ca-trust                           ║
╠══════════════════════════════════════════════════════════════════╣
║ VERIFY CERTIFICATE                                               ║
║   openssl x509 -in cert.crt -text -noout                         ║
║   openssl verify -CAfile ca.crt server.crt                       ║
╚══════════════════════════════════════════════════════════════════╝

Appendix: Platform Trust Installation Reference

Platform Location/Command Requires Admin Notes
macOS Keychain Access → System 🟢 Yes GUI or security command
Windows certutil / MMC 🟢 Yes Use LocalMachine\Root store
Ubuntu/Debian /usr/local/share/ca-certificates/ 🟢 Yes Run update-ca-certificates
RHEL/CentOS /etc/pki/ca-trust/source/anchors/ 🟢 Yes Run update-ca-trust
Arch /etc/ca-certificates/trust-source/anchors/ 🟢 Yes Run trust extract-compat
Android (User) Settings → Security → Install cert 🟡 No Shows “monitored” warning
Android (System) /system/etc/security/cacerts/ 🔴 Root Requires root access
iOS/iPadOS Profile install + Trust Settings 🟡 No Two-step process required

Legend:

  • 🟢 Standard admin access
  • 🟡 User can do it, with limitations
  • 🔴 Requires special access (root/jailbreak)

Security Considerations

Don’t shoot yourself in the foot

  1. Protect your CA private key – If compromised, attackers can issue trusted certificates for any domain
  2. Use strong passphrases – The CA key passphrase should be complex and stored securely
  3. Set reasonable validity periods – CA: 5-10 years, Server certs: 1 year, Client certs: 1 year or less
  4. Keep an inventory – Track what certificates you’ve issued and when they expire
  5. Don’t use self-signed CAs for public services – This is for internal/homelab use only
  6. Revocation is hard – Self-signed CAs don’t have CRL/OCSP infrastructure. If a cert is compromised, you need to manually remove trust or reissue

Conclusion

You now have the power to:

  1. Create your own Certificate Authority with proper key management
  2. Issue server certificates for HTTPS services in your homelab
  3. Issue client certificates for mutual TLS authentication
  4. Deploy CA trust across macOS, Windows, Linux, Android, and iOS

No more certificate warnings. No more “proceed anyway” clicks. No more browser shame.


Fun fact: The average enterprise manages over 50,000 certificates. Your homelab probably has fewer than 50. Congratulations, you’re already ahead of most Fortune 500 IT departments in terms of certificate-to-headache ratio.


Stay encrypted, stay curious 🔐

Leave a Reply

Your email address will not be published. Required fields are marked *