Last active
August 31, 2025 16:42
-
-
Save mattwillsher/d5bb138d26f67eb54e1cf1b7613f696f to your computer and use it in GitHub Desktop.
Generate CA cert/key and server cert/key for localhost use.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| #!/usr/bin/env bash | |
| set -e | |
| OUTPUT_DIR=${OUTPUT_DIR:-"out"} | |
| SUBDOMAIN=${1:-"my"} | |
| CA_CERT="certs/ca.cert.pem" | |
| CA_KEY="private/ca.key.pem" | |
| LOCALHOST_CERT="certs/$SUBDOMAIN.localhost.cert.pem" | |
| LOCALHOST_KEY="private/$SUBDOMAIN.localhost.key.pem" | |
| OPENSSL_CNF="openssl.cnf" | |
| mkdir -p "$OUTPUT_DIR" || true | |
| cd "$OUTPUT_DIR" | |
| # === Setup directories === | |
| mkdir -p certs private newcerts | |
| chmod 700 private | |
| touch index.txt | |
| echo 1000 >serial | |
| # === Write OpenSSL config === | |
| cat >"$OPENSSL_CNF" <<EOF | |
| [ ca ] | |
| default_ca = CA_default | |
| [ CA_default ] | |
| dir = . | |
| certs = certs | |
| crl_dir = crl | |
| database = index.txt | |
| new_certs_dir = newcerts | |
| certificate = "$CA_CERT" | |
| private_key = "$CA_KEY" | |
| serial = serial | |
| default_md = sha256 | |
| # policy = policy_strict | |
| x509_extensions = v3_ca | |
| # [ policy_strict ] | |
| # countryName = match | |
| # stateOrProvinceName = match | |
| # organizationName = match | |
| # commonName = supplied | |
| [ req ] | |
| default_bits = 4096 | |
| default_md = sha256 | |
| prompt = no | |
| # distinguished_name = req_distinguished_name | |
| x509_extensions = v3_ca | |
| # These don't seem to be needed. Remove in future | |
| # [ req_distinguished_name ] | |
| # C = Country | |
| # ST = State | |
| # O = Organization | |
| [ v3_ca ] | |
| subjectKeyIdentifier = hash | |
| authorityKeyIdentifier = keyid:always,issuer | |
| basicConstraints = critical, CA:true, pathlen:0 | |
| keyUsage = critical, keyCertSign, cRLSign | |
| nameConstraints = critical, permitted;DNS:localhost, permitted;DNS:.localhost, permitted;IP:127.0.0.1/255.255.255.255, permitted;IP:0:0:0:0:0:0:0:1/ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff | |
| [ server_cert ] | |
| basicConstraints = CA:FALSE | |
| nsCertType = server | |
| nsComment = "Localhost Server Certificate" | |
| subjectKeyIdentifier = hash | |
| authorityKeyIdentifier = keyid,issuer | |
| keyUsage = critical, digitalSignature, keyEncipherment | |
| extendedKeyUsage = serverAuth | |
| subjectAltName = @alt_names | |
| [ alt_names ] | |
| DNS.1 = $SUBDOMAIN.localhost | |
| DNS.2 = *.$SUBDOMAIN.localhost | |
| IP.1 = 127.0.0.1 | |
| IP.2 = ::1 | |
| EOF | |
| function generate_root_ca { | |
| if [ -f "$CA_CERT" ] && [ -f "$CA_KEY" ]; then | |
| echo "Root CA already exists, skipping generation." | |
| return | |
| fi | |
| openssl req -config "$OPENSSL_CNF" \ | |
| -new -x509 -days 366 -sha256 \ | |
| -extensions v3_ca \ | |
| -subj "/CN=My localhost CA" \ | |
| -nodes \ | |
| -keyout "$CA_KEY" \ | |
| -out "$CA_CERT" | |
| chmod 400 "$CA_KEY" | |
| chmod 444 "$CA_CERT" | |
| } | |
| function generate_server_cert { | |
| if [ -f "$LOCALHOST_CERT" ] && [ -f "$LOCALHOST_KEY" ]; then | |
| echo "Localhost cert and key already exist, skipping generation." | |
| return | |
| fi | |
| echo "Generating localhost cert and key for $SUBDOMAIN.localhost." | |
| openssl genrsa -out "$LOCALHOST_KEY" 2048 | |
| chmod 400 "$LOCALHOST_KEY" | |
| openssl req -new -sha256 \ | |
| -key "$LOCALHOST_KEY" \ | |
| -subj "/CN=$SUBDOMAIN.localhost" \ | |
| -nodes \ | |
| -out localhost.csr.pem | |
| openssl x509 -req -days 365 -sha256 \ | |
| -in localhost.csr.pem \ | |
| -CA "$CA_CERT" -CAkey "$CA_KEY" -CAcreateserial \ | |
| -extfile "$OPENSSL_CNF" -extensions server_cert \ | |
| -out "$LOCALHOST_CERT" | |
| chmod 444 "$LOCALHOST_CERT" | |
| rm localhost.csr.pem | |
| } | |
| generate_root_ca | |
| generate_server_cert | |
| cat <<'EOF' | |
| # PowerShell commands to manage the certificates, needs administrative privileges | |
| # To add the cert | |
| Import-Certificate -FilePath \"$OUTPUT_DIR/$CA_CERT\" -CertStoreLocation \"Cert:\LocalMachine\My\" | |
| # To remove the certificate | |
| $cert = Get-ChildItem -Path Cert:\LocalMachine\My | Where-Object { $_.Subject -like "*CN=My localhost CA*" } | |
| if ($cert) { | |
| Remove-Item -Path $cert.PSPath | |
| } | |
| EOF |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment