A lightweight, user-friendly command-line tool for managing your own Certificate Authority and generating certificates for development and testing. It is based off of mkcert, but mkcert hasn't been updated in a while and is seems to be stale and not keeping up with morn modern CA requirments like intermediate certs which, even in dev environments is reqired. It is designed to be a drop in replacement for mkcert (as of Oct 10, 2025).
- Simple CA Management: Create and manage a root CA with intermediate CA in one command
- Multiple Certificate Types: TLS server, client authentication, and S/MIME certificates
- Smart Input Detection: Automatically detects domains, IPs, and email addresses
- ECDSA Support: Generate certificates with ECDSA keys for modern crypto
- PKCS#12 Export: Create
.p12/.pfxfiles for legacy application compatibility - CSR Support: Generate certificates from existing Certificate Signing Requests
- No Dependencies: Single binary with no external runtime dependencies
Download the latest release for your platform from the releases page.
Linux (AMD64):
wget https://github.com/chriskacerguis/certy/releases/latest/download/certy-linux-amd64
chmod +x certy-linux-amd64
sudo mv certy-linux-amd64 /usr/local/bin/certymacOS (Apple Silicon):
wget https://github.com/chriskacerguis/certy/releases/latest/download/certy-darwin-arm64
chmod +x certy-darwin-arm64
sudo mv certy-darwin-arm64 /usr/local/bin/certymacOS (Intel):
wget https://github.com/chriskacerguis/certy/releases/latest/download/certy-darwin-amd64
chmod +x certy-darwin-amd64
sudo mv certy-darwin-amd64 /usr/local/bin/certyWindows:
Download certy-windows-amd64.exe from the releases page and add it to your PATH.
git clone https://github.com/chriskacerguis/certy.git
cd certy
go build -ldflags "-X main.version=1.0.1" -o certy
sudo mv certy /usr/local/bin/# Initialize the CA infrastructure (one-time setup)
certy -install
# Generate a TLS certificate for multiple domains/IPs
certy example.com "*.example.com" example.test localhost 127.0.0.1 ::1
# Generate an S/MIME certificate
certy [email protected]
# Generate a client authentication certificate
certy -client client.example.comBefore generating any certificates, you must initialize the CA:
certy -installThis creates:
- Root CA (valid for 10 years)
- Intermediate CA (valid for 5 years)
- Configuration file at
~/.certy/config.yml - Serial number tracker
All CA files are stored in ~/.certy/ by default.
You can specify a custom directory for CA files in three ways (in order of priority):
1. Using the -ca-dir flag (highest priority):
# Install CA in a custom directory
certy -ca-dir /path/to/ca -install
# Use custom CA directory for certificate generation
certy -ca-dir /path/to/ca example.com2. Using the CAROOT environment variable:
# Set CAROOT for the current session
export CAROOT=/path/to/ca
certy -install
certy example.com
# Or set it per-command
CAROOT=/path/to/ca certy -install3. Default location: ~/.certy/ (lowest priority)
Check where your CA is located:
# Print the current CA directory
certy -CAROOT
# With environment variable set
export CAROOT=/tmp/my-ca
certy -CAROOT
# Output: /tmp/my-ca
# Flag takes priority over environment variable
certy -ca-dir ./custom -CAROOT
# Output: /Users/you/path/to/customThis is useful for:
- Managing multiple CAs (e.g., dev, staging, production)
- Storing CA files in a specific location (e.g., encrypted volume)
- Team shared CA directories
- Compatibility with tools that use
CAROOT(like mkcert)
# Single domain
certy example.com
# Multiple domains and IPs
certy example.com "*.example.com" 127.0.0.1 ::1
# With custom output paths
certy -cert-file ./certs/server.pem -key-file ./certs/server-key.pem example.comOutput files follow the pattern: <first-domain>+<count>.pem and <first-domain>+<count>-key.pem
Automatically detected when input contains an email address:
certy [email protected]certy -client client.example.comcerty -ecdsa example.comFor applications that require .p12 or .pfx format:
# No password (backward compatible)
certy -pkcs12 example.com
# With password protection
certy -pkcs12 -p12-password "MySecurePassword!" example.com
# Custom PKCS#12 path with password
certy -pkcs12 -p12-file ./cert.p12 -p12-password "secret" example.comNote: PKCS#12 files support optional password protection. Use -p12-password flag to set a password, or omit it for no protection (backward compatible).
certy -csr request.csr -cert-file signed.pemCerty supports generating Certificate Revocation Lists (CRLs) for managing revoked certificates. This is especially important for production-like environments where you need to invalidate compromised certificates.
First, add a CRL distribution point URL to your configuration (~/.certy/config.yml):
crl_url: http://crl.example.com/intermediate.crlThis URL will be embedded in all certificates issued after you run -install with this configuration. Reinstall the CA to apply:
# Edit config.yml to add crl_url, then:
certy -install # Updates the intermediate CA with CRL distribution pointTo revoke a certificate by its serial number:
# Find the serial number
openssl x509 -in certificate.pem -noout -serial
# Revoke it (serial number in decimal or hex)
certy -revoke 1
# or with hex serial from openssl
certy -revoke 0x01Revocation reasons (optional, defaults to 0):
0- Unspecified1- Key compromise2- CA compromise3- Affiliation changed4- Superseded5- Cessation of operation
After revoking certificates, generate an updated CRL:
# Generate CRL in default location (~/.certy/crl.pem)
certy -gencrl
# Or specify custom output path
certy -gencrl /var/www/crl/intermediate.crlThe CRL file:
- Contains all revoked certificates with their serial numbers and revocation dates
- Is signed by the intermediate CA
- Has a validity period of 30 days
- Should be regenerated periodically and published at the CRL URL
Use OpenSSL to verify that a certificate hasn't been revoked:
openssl verify -CAfile ~/.certy/rootCA.pem \
-untrusted ~/.certy/intermediateCA.pem \
-crl_check \
-CRLfile ~/.certy/crl.pem \
certificate.pemExample output for revoked certificate:
CN=test.example.com
error 23 at 0 depth lookup: certificate revoked
error certificate.pem: verification failed
# 1. Configure CRL URL
echo "crl_url: http://crl.example.com/intermediate.crl" >> ~/.certy/config.yml
# 2. Reinstall CA to add CRL distribution point
certy -install
# 3. Generate certificates (they now include CRL URL)
certy example.com
# 4. If a certificate needs to be revoked:
certy -revoke 1
# 5. Generate updated CRL and publish it
certy -gencrl /var/www/crl/intermediate.crl
# 6. Verify certificate status
openssl verify -CAfile ~/.certy/rootCA.pem \
-untrusted ~/.certy/intermediateCA.pem \
-crl_check \
-CRLfile /var/www/crl/intermediate.crl \
example.com.pemImportant: The CRL file should be:
- Published at the URL configured in
crl_url - Regenerated regularly (before the 30-day validity expires)
- Updated whenever certificates are revoked
Configuration is stored at ~/.certy/config.yml:
default_validity_days: 365 # Certificate validity (1 year)
root_ca_validity_days: 3650 # Root CA validity (10 years)
intermediate_ca_validity_days: 1825 # Intermediate CA validity (5 years)
default_key_type: rsa # Key algorithm (rsa or ecdsa)
default_key_size: 2048 # RSA key size
crl_url: "" # Optional: CRL distribution point URLYou can edit this file to customize defaults. CLI flags always override config values.
certy localhost 127.0.0.1 ::1
# Outputs: localhost+2.pem and localhost+2-key.pemcerty "*.dev.example.com" dev.example.comcerty app.example.com api.example.com cdn.example.comcerty -pkcs12 [email protected]
# Outputs: user-at-example.com.pem, user-at-example.com-key.pem, user-at-example.com.p12The PKCS#12 file contains:
- Your S/MIME certificate
- Your private key
- The intermediate CA certificate (for chain validation)
- No password (empty password for simplicity)
This .p12 file can be imported directly into:
- Email clients (Thunderbird, Outlook, Apple Mail)
- Web browsers (Chrome, Firefox, Safari)
- Mobile devices (iOS, Android)
Import example (macOS):
# Double-click the .p12 file, or:
open user-at-example.com.p12
# Enter empty password when promptedImport example (Linux with Thunderbird):
# Settings → Privacy & Security → Certificates → Manage Certificates
# → Your Certificates → Import → Select the .p12 filecerty -ecdsa -pkcs12 modern.example.com# Create separate CAs for different environments
certy -ca-dir ./ca-dev -install
certy -ca-dir ./ca-staging -install
certy -ca-dir ./ca-prod -install
# Generate certificates for each environment
certy -ca-dir ./ca-dev dev.example.com
certy -ca-dir ./ca-staging staging.example.com
certy -ca-dir ./ca-prod example.comAll certificates are signed by the intermediate CA, which is signed by the root CA:
Root CA (self-signed, 10 years)
└── Intermediate CA (signed by root, 5 years)
└── End-entity certificates (signed by intermediate, 1 year)
This follows best practices by keeping the root CA offline and using the intermediate CA for day-to-day operations.
To trust certificates generated by certy, you need to add the root CA to your system's trust store:
sudo security add-trusted-cert -d -r trustRoot -k /Library/Keychains/System.keychain ~/.certy/rootCA.pemsudo cp ~/.certy/rootCA.pem /usr/local/share/ca-certificates/certy-root-ca.crt
sudo update-ca-certificatescertutil -addstore -f "ROOT" %USERPROFILE%\.certy\rootCA.pem- CA private keys are not password protected
- PKCS#12 files use empty passwords
- All private keys are stored in plain text at
~/.certy/
Do not use this for production certificates or security-critical applications.
Generated files use sanitized filenames based on the first input:
@→-at-*→wildcard:→-/→-
Examples:
[email protected]→user-at-example.com.pem*.example.com→wildcard.example.com.pem
Run certy -install to initialize the CA infrastructure.
Ensure your CSR file is valid:
openssl req -in request.csr -noout -verifyVerify the certificate chain:
openssl verify -CAfile ~/.certy/rootCA.pem -untrusted ~/.certy/intermediateCA.pem certificate.pemAdditional documentation is available in the docs/ directory:
- Testing Guide - Running and writing tests
- Test Coverage - Coverage statistics and goals
- Security Policy - Security considerations and vulnerability reporting
- Release Notes - Version history and changelog
MIT License - see LICENSE file for details.
Contributions welcome! Please open an issue or pull request on GitHub.
Built with Go using standard library crypto packages and: