mkcert Cheat Sheet
Overview
mkcert is a simple zero-configuration tool for making locally-trusted development certificates. It automatically creates and installs a local Certificate Authority (CA) in the system trust store, then generates certificates signed by that CA. Browsers and other tools will trust these certificates without any warnings or manual configuration.
Unlike self-signed certificates that require manual trust configuration or generate browser warnings, mkcert handles the entire trust chain setup automatically. It works across Linux, macOS, and Windows, and supports Chrome, Firefox, Java, and system certificate stores.
Installation
# macOS
brew install mkcert
brew install nss # Required for Firefox support
# Linux (Debian/Ubuntu)
sudo apt install libnss3-tools # For Firefox support
curl -JLO "https://dl.filippo.io/mkcert/latest?for=linux/amd64"
chmod +x mkcert-v*-linux-amd64
sudo mv mkcert-v*-linux-amd64 /usr/local/bin/mkcert
# Arch Linux
sudo pacman -S mkcert
# Windows
choco install mkcert
# or
scoop install mkcert
# Go install
go install filippo.io/mkcert@latest
# Verify
mkcert --version
Setup
# Install the local CA (do this once)
mkcert -install
# This creates a CA certificate and adds it to:
# - macOS: System Keychain
# - Linux: NSS database (for Firefox) and system trust store
# - Windows: Certificate Store
# Check CA location
mkcert -CAROOT
# Uninstall the CA (when done with local dev)
mkcert -uninstall
Core Commands
| Command | Description |
|---|---|
mkcert -install | Install the local CA in trust stores |
mkcert -uninstall | Uninstall the local CA |
mkcert domain.test | Generate cert for a domain |
mkcert -CAROOT | Print CA root directory |
mkcert -cert-file <f> -key-file <f> | Custom output file names |
mkcert -p12-file <f> | Generate PKCS#12 format |
mkcert -client | Generate client certificate |
mkcert -ecdsa | Use ECDSA key instead of RSA |
mkcert -pkcs12 | Generate PKCS#12 keystore |
Generating Certificates
Basic Usage
# Single domain
mkcert localhost
# Multiple domains and IPs
mkcert localhost 127.0.0.1 ::1
# Custom domain names
mkcert myapp.local api.myapp.local
# Wildcard certificates
mkcert "*.myapp.local" myapp.local
# Full example with all local names
mkcert localhost 127.0.0.1 ::1 myapp.local "*.myapp.local"
# Output: localhost+4.pem and localhost+4-key.pem
Custom Output Files
# Custom file names
mkcert -cert-file cert.pem -key-file key.pem localhost
# PKCS#12 format (for Java/Spring)
mkcert -pkcs12 localhost
# Output: localhost.p12
# Custom PKCS#12 file name
mkcert -p12-file keystore.p12 localhost 127.0.0.1
# ECDSA key (smaller, faster)
mkcert -ecdsa localhost
# Client certificate
mkcert -client myuser@myapp.local
Configuration
Using with Web Servers
Node.js / Express
const https = require('https');
const fs = require('fs');
const express = require('express');
const app = express();
app.get('/', (req, res) => res.send('Hello HTTPS!'));
const options = {
key: fs.readFileSync('./localhost-key.pem'),
cert: fs.readFileSync('./localhost.pem')
};
https.createServer(options, app).listen(3000, () => {
console.log('HTTPS server running at https://localhost:3000');
});
Nginx
server {
listen 443 ssl;
server_name localhost myapp.local;
ssl_certificate /path/to/localhost+1.pem;
ssl_certificate_key /path/to/localhost+1-key.pem;
location / {
proxy_pass http://localhost:3000;
}
}
Python (Flask)
from flask import Flask
app = Flask(__name__)
if __name__ == '__main__':
app.run(
host='0.0.0.0',
port=5000,
ssl_context=('localhost.pem', 'localhost-key.pem')
)
Go
package main
import (
"log"
"net/http"
)
func main() {
http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
w.Write([]byte("Hello HTTPS!"))
})
log.Fatal(http.ListenAndServeTLS(":8443",
"localhost.pem", "localhost-key.pem", nil))
}
Using with Docker
# docker-compose.yml
version: '3.8'
services:
app:
build: .
ports:
- "443:443"
volumes:
- ./certs:/certs:ro
environment:
- TLS_CERT=/certs/localhost.pem
- TLS_KEY=/certs/localhost-key.pem
# Generate certs in a certs/ directory
mkdir certs
mkcert -cert-file certs/localhost.pem -key-file certs/localhost-key.pem \
localhost 127.0.0.1 ::1
Advanced Usage
Custom CA Root Location
# Set custom CA root directory
export CAROOT=/path/to/custom/ca
mkcert -install
# Share CA with team (copy rootCA.pem only, NEVER share rootCA-key.pem)
cp "$(mkcert -CAROOT)/rootCA.pem" ./shared-ca.pem
Java/Spring Boot
# Generate PKCS#12 keystore for Spring Boot
mkcert -pkcs12 -p12-file keystore.p12 localhost 127.0.0.1
# application.properties
server.port=8443
server.ssl.key-store=classpath:keystore.p12
server.ssl.key-store-type=PKCS12
server.ssl.key-store-password=changeit
Webpack Dev Server
// webpack.config.js
const fs = require('fs');
module.exports = {
devServer: {
https: {
key: fs.readFileSync('./localhost-key.pem'),
cert: fs.readFileSync('./localhost.pem'),
},
host: 'localhost',
port: 8080,
},
};
Vite
// vite.config.js
import fs from 'fs';
import { defineConfig } from 'vite';
export default defineConfig({
server: {
https: {
key: fs.readFileSync('./localhost-key.pem'),
cert: fs.readFileSync('./localhost.pem'),
},
},
});
Troubleshooting
| Issue | Solution |
|---|---|
| Firefox still shows warning | Install nss / libnss3-tools and re-run mkcert -install |
| Certificate not trusted | Run mkcert -install again; restart browser |
| Permission denied on install | Run with sudo on Linux; Admin PowerShell on Windows |
| Docker container doesn’t trust cert | Mount the CA cert and add to container trust store |
| Wildcard cert not matching | Wildcards only match one level; use "*.app.local" |
| CAROOT permissions | Protect rootCA-key.pem; never share the private key |
# Verify certificate details
openssl x509 -in localhost.pem -text -noout
# Check CA is installed
mkcert -CAROOT
ls "$(mkcert -CAROOT)"
# Test HTTPS connection
curl -v https://localhost:3000
# Reinstall CA after OS update
mkcert -uninstall
mkcert -install