Stop Wrestling with Self-Signed Certs! Use mkcert Instead
You've been there. You're fifteen minutes into building that killer new feature, your local server is humming, and you hit https://localhost:3000 expecting smooth sailing. Instead? BAM. A blood-red security warning slaps your screen. Your browser treats your carefully crafted development environment like a sketchy phishing site from 2004.
You click "Advanced." You click "Proceed anyway." You do this fifty times a day. And if you're working with Service Workers, WebRTC, or any modern API that demands secure contexts? Those self-signed certificate errors aren't just annoying—they're blocking your entire workflow.
Here's the dirty secret nobody tells junior developers: managing certificates for local development is a rathole of suffering. You can generate self-signed certs with OpenSSL, sure. But then you're manually installing them into trust stores, fighting Firefox's NSS database, discovering Chrome doesn't use the system store on Linux, and wondering why your perfectly valid cert still throws NET::ERR_CERT_AUTHORITY_INVALID.
What if I told you there's a tool that eliminates this pain entirely? No configuration files. No OpenSSL incantations. No browser gymnastics. Just trusted certificates that work.
Enter mkcert—the brainchild of cryptography wizard Filippo Valsorda. This unassuming CLI tool has quietly become the secret weapon of senior developers who refuse to waste another second on certificate busywork. In this deep dive, I'll show you exactly why mkcert is dominating local development workflows, how to wield it like a pro, and why you'll never touch openssl req again.
What is mkcert? The Zero-Config Certificate Revolution
mkcert is a simple, zero-configuration tool for making locally-trusted development certificates with any names you want. Created by Filippo Valsorda, a former Go security lead at Google and renowned cryptography engineer, mkcert solves a problem that has plagued developers for decades: how do you get valid HTTPS in local development without the pain?
The tool's genius lies in its radical simplicity. Instead of generating self-signed certificates that browsers reject, mkcert automatically creates and installs a local Certificate Authority (CA) directly into your system's trust store—and Firefox's, and Java's, and wherever else you need it. This CA then signs certificates for whatever domains you specify, and because your system trusts the CA, it trusts the certificates automatically.
No browser warnings. No --ignore-certificate-errors flags. No more explaining to your QA team why they need to click through scary security pages.
mkcert has exploded in popularity because it strikes a perfect balance: it's powerful enough for complex development scenarios yet simple enough that you'll have it running in under 60 seconds. The project has earned over 50,000 GitHub stars, been adopted by major frameworks, and become an essential tool in the modern developer's toolkit.
The philosophy behind mkcert is clear: development environment setup should be frictionless. Real CAs won't issue certificates for localhost or *.test domains. Self-signed certs break user experience and disable security-sensitive APIs. Running your own CA manually requires arcane knowledge of PKI infrastructure that most developers simply don't have—or want. mkcert bridges this gap with elegant automation.
Critically, mkcert is explicitly designed for development only. It is not a production CA replacement, and its security model reflects this. The tool generates a unique CA per machine, never shares keys, and warns aggressively about protecting your rootCA-key.pem file.
Key Features That Make mkcert Irreplaceable
mkcert's feature set reveals the depth of thought behind its deceptively simple interface:
Automatic CA Installation Across Platforms
mkcert doesn't just create a CA—it installs it everywhere that matters. macOS system store, Windows certificate manager, Linux variants using update-ca-trust, update-ca-certificates, or trust, Firefox's independent NSS database, Chrome/Chromium, and even Java's keystore when JAVA_HOME is configured. The TRUST_STORES environment variable lets you target specific stores if you need surgical precision.
Wildcard and Multi-Domain Certificates
Generate certificates for multiple domains and wildcards in a single command. Need example.com, *.example.com, localhost, 127.0.0.1, and ::1 all in one cert? mkcert handles it effortlessly, producing SAN (Subject Alternative Name) certificates that satisfy modern browser requirements.
Multiple Output Formats
Beyond standard PEM files, mkcert supports PKCS #12 (.p12/.pfx) for legacy applications, ECDSA keys for modern performance requirements, and custom file paths via -cert-file and -key-file flags. The -client flag even generates certificates for mutual TLS authentication scenarios.
CSR Support for Existing Workflows
Already have a certificate signing request from another tool? mkcert can sign it with your local CA using the -csr flag, integrating cleanly into established infrastructure without forcing wholesale migration.
S/MIME Certificate Generation
Pass an email address instead of a domain, and mkcert automatically generates an S/MIME certificate for email signing and encryption testing. This automatic format detection showcases the tool's thoughtful design.
Cross-Platform Consistency
Whether your team runs macOS, Windows, or a dozen Linux distributions, mkcert provides identical workflows. The installation methods adapt to each platform's package ecosystem—Homebrew, MacPorts, Chocolatey, Scoop, APT, YUM, Pacman, or pre-built binaries—while the command interface remains perfectly consistent.
Mobile Device Support
Development testing on actual devices? Export your CA certificate via mkcert -CAROOT and install it on iOS or Android. The tool provides clear documentation for enabling full trust on iOS and user root certificates in Android development builds.
Real-World Use Cases Where mkcert Shines
Modern Web Development with Secure Context APIs
Service Workers, Payment Request API, Web Authentication, and Geolocation require secure contexts. Testing these on localhost with self-signed certs often fails unpredictably. mkcert provides genuinely trusted HTTPS that satisfies these requirements without workarounds.
Microservices and API Gateway Development
When you're running five services locally, each on different ports, with an API gateway handling routing? You need certificates for api.local, auth.local, payments.local, and wildcards for dynamic subdomains. mkcert generates these in one command, and your gateway configuration stays clean.
OAuth and OIDC Integration Testing
Third-party OAuth providers reject redirect URIs with invalid certificates. Testing your integration locally used to require tunneling services or complex nginx configurations. With mkcert, auth.myapp.test gets a real certificate, and your OAuth flows work identically to production.
Cross-Browser Testing
Firefox, Chrome, Safari, Edge—each handles certificates differently. mkcert's comprehensive trust store installation means consistent behavior across all browsers. No more discovering that your cert works in Chrome but Firefox throws errors because you missed the NSS database.
Mobile Application Backend Development
Mobile apps connecting to local development servers face strict certificate validation. mkcert's exported CA installation on iOS and Android devices lets you test real network behavior without disabling ATS (App Transport Security) or using dangerous allowsArbitraryLoads settings.
Step-by-Step Installation & Setup Guide
Getting mkcert running takes under two minutes. Here's the complete setup for every major platform.
macOS Installation
Using Homebrew (recommended):
# Install mkcert itself
brew install mkcert
# Install nss for Firefox support (critical step!)
brew install nss
Or with MacPorts:
sudo port selfupdate
sudo port install mkcert
sudo port install nss # if you use Firefox
Linux Installation
First, install certutil for certificate management:
# Debian/Ubuntu
sudo apt install libnss3-tools
# RHEL/CentOS/Fedora
sudo yum install nss-tools
# Arch Linux
sudo pacman -S nss
# openSUSE/SLES
sudo zypper install mozilla-nss-tools
Then install mkcert via Homebrew on Linux:
brew install mkcert
Or use pre-built binaries for maximum portability:
# Download latest release for your architecture
curl -JLO "https://dl.filippo.io/mkcert/latest?for=linux/amd64"
# Make executable
chmod +x mkcert-v*-linux-amd64
# Install system-wide
sudo cp mkcert-v*-linux-amd64 /usr/local/bin/mkcert
Arch users get official package support:
sudo pacman -Syu mkcert
Windows Installation
With Chocolatey:
choco install mkcert
Or Scoop:
scoop bucket add extras
scoop install mkcert
Important: Run installation commands as Administrator if you encounter permission issues.
The Essential First Step: Install Your Local CA
Regardless of platform, run this once after installation:
mkcert -install
You'll see output like:
Created a new local CA 💥
The local CA is now installed in the system trust store! ⚡️
The local CA is now installed in the Firefox trust store (requires browser restart)! 🦊
This creates your machine's unique Certificate Authority and establishes trust across all supported stores. Protect the generated rootCA-key.pem file—it holds complete power to intercept secure requests from your machine.
REAL Code Examples: mkcert in Action
Let's walk through actual commands from the mkcert repository, explained with the depth you need to use them confidently.
Example 1: Basic Certificate Generation
The quintessential mkcert command—generate a certificate for multiple domains and IP addresses:
mkcert example.com "*.example.com" example.test localhost 127.0.0.1 ::1
What's happening here?
example.com— exact domain match"*.example.com"— wildcard for all subdomains (quotes prevent shell expansion)example.test— reserved TLD safe for local testinglocalhost— standard local development hostname127.0.0.1— IPv4 loopback address::1— IPv6 loopback address
Output:
Created a new certificate valid for the following names 📜
- "example.com"
- "*.example.com"
- "example.test"
- "localhost"
- "127.0.0.1"
- "::1"
The certificate is at "./example.com+5.pem" and the key at "./example.com+5-key.pem" ✅
The +5 in filenames indicates five additional SANs beyond the primary domain. These PEM files are standard X.509 certificates and RSA private keys—compatible with nginx, Apache, Node.js, Python's ssl module, and virtually every server software.
Example 2: Custom Output Paths for Server Configuration
When your application expects specific certificate locations, use advanced options:
mkcert -key-file key.pem -cert-file cert.pem example.com *.example.com
Critical syntax note: These flags must precede the domain list. This generates:
key.pem— your private key (protect this!)cert.pem— your certificate with full SAN list
Perfect for Docker containers, CI/CD pipelines, or frameworks with fixed path expectations.
Example 3: PKCS #12 for Legacy Applications
Some enterprise tools and older Microsoft products require .pfx or .p12 format:
mkcert -pkcs12 example.com
This generates example.com.p12 containing both certificate and key in a single password-protected file. While modern infrastructure prefers separate PEM files, this legacy support prevents integration headaches with stubborn tools.
Example 4: Node.js Integration
Node.js does not use the system root store—a common trap that causes mysterious certificate failures despite mkcert working everywhere else. The solution:
export NODE_EXTRA_CA_CERTS="$(mkcert -CAROOT)/rootCA.pem"
How this works:
mkcert -CAROOTprints your CA storage directoryrootCA.pemis your CA's public certificate (safe to share, unlikerootCA-key.pem)NODE_EXTRA_CA_CERTStells Node.js to trust this additional CA
Add this to your shell profile or .env files for persistent configuration across sessions.
Example 5: S/MIME for Email Development
Testing email encryption or signed messages? Pass an email address:
mkcert filippo@example.com
mkcert automatically detects the email format and generates an S/MIME certificate instead of a TLS server certificate. This same-domain flexibility demonstrates how the tool adapts to your needs without flag proliferation.
Advanced Usage & Best Practices
Separate CAs for Different Projects
Use the $CAROOT environment variable to isolate certificate authorities:
export CAROOT="$HOME/.local/share/mkcert-project-a"
mkcert -install
This creates independent trust chains, useful when collaborating with external teams or maintaining strict separation between client projects.
Selective Trust Store Installation
Speed up installation or avoid modifying specific stores:
TRUST_STORES=system,java mkcert -install
Options are system, java, and nss (Firefox). Omit nss if you don't use Firefox for faster setup.
Certificate Transparency for Debugging
Inspect generated certificates with OpenSSL to verify SANs and validity:
openssl x509 -in example.com+5.pem -text -noout | grep -A2 "Subject Alternative Name"
Team Onboarding Automation
Commit a script to your repository:
#!/bin/bash
set -e
# Ensure mkcert is installed
command -v mkcert >/dev/null 2>&1 || { echo "Install mkcert first: https://github.com/FiloSottile/mkcert"; exit 1; }
# Install CA if not already present
mkcert -install 2>/dev/null || true
# Generate project certificates
mkdir -p certs
mkcert -cert-file certs/local.crt -key-file certs/local.key \
app.localhost api.localhost "*.localhost"
echo "Certificates ready in ./certs/"
Security Hygiene
- Never commit
rootCA-key.pemto version control - Add
*-key.pemto.gitignore - Rotate your CA periodically with
mkcert -uninstall && mkcert -install - Use
.testor.localhostTLDs to prevent accidental conflicts with real domains
Comparison with Alternatives
| Tool | Configuration | Browser Trust | Wildcard Support | Mobile Support | Learning Curve |
|---|---|---|---|---|---|
| mkcert | Zero-config | Automatic | Yes | Exportable CA | Minimal |
| OpenSSL self-signed | Manual | Broken by default | Manual SAN config | Manual install | Steep |
| Let's Encrypt (staging) | DNS/HTTP challenge | Trusted | Yes | Yes | Complex for local |
| mkcert equivalents (local-ssl-proxy) | Minimal | System-dependent | No | No | Low |
| Cloudflare Origin CA | Requires Cloudflare | Partial | Yes | No | Medium |
| Commercial dev certs | Purchase process | Trusted | Varies | Varies | Medium |
Why mkcert wins: The combination of genuine zero-configuration setup, automatic multi-store trust installation, and wildcard flexibility is unmatched. OpenSSL requires dozens of commands for equivalent results. Let's Encrypt's validation challenges are impractical for ephemeral local environments. Proxy tools don't solve the fundamental trust problem—they just hide it.
FAQ: Your mkcert Questions Answered
Is mkcert safe for production use?
No. mkcert is explicitly designed for development environments only. The local CA model isn't suitable for public-facing services. For production, use Let's Encrypt, a commercial CA, or your organization's internal PKI.
Can I use mkcert with Docker containers?
Absolutely. Generate certificates on your host, mount them as volumes, or install the CA inside containers. For Docker Compose, volume-mount your rootCA.pem and set NODE_EXTRA_CA_CERTS or equivalent for your runtime.
Why does Firefox still show warnings after mkcert -install?
You likely missed brew install nss (macOS) or sudo apt install libnss3-tools (Linux). Firefox maintains its own certificate database separate from the system store. Restart Firefox after fixing this.
How do I uninstall mkcert completely?
Run mkcert -uninstall to remove the CA from all trust stores, then delete the CA files from $(mkcert -CAROOT). Finally, uninstall the binary via your package manager.
Can I share my mkcert CA with teammates?
Share only rootCA.pem (the public certificate), never rootCA-key.pem (the private key). Better practice: each teammate runs mkcert -install to create their own unique CA, avoiding key distribution risks.
Does mkcert work with Kubernetes or minikube?
Yes. Generate certificates for your minikube ingress domains, then configure the ingress controller with the resulting PEM files. For cluster-wide trust, you'll need to distribute the CA certificate to nodes.
What domains should I use for local development?
Prefer .test, .localhost, or .invalid—these are reserved TLDs that can never conflict with real domains. Avoid .dev (Google owns it and forces HSTS) and .local (mDNS conflicts).
Conclusion: Reclaim Your Development Flow
Certificate management was never meant to consume your cognitive bandwidth. Every minute spent fighting browser warnings, debugging TLS handshakes, or explaining to teammates why their local environment broke is a minute stolen from building what matters.
mkcert represents a philosophical victory in developer tooling: complex cryptographic operations, abstracted into commands so intuitive they feel inevitable. Filippo Valsorda's creation has earned its place alongside git, curl, and jq as essential infrastructure—tools so good they disappear into your workflow.
The next time you spin up a local server, skip the self-signed certificate dance. Skip the OpenSSL man pages. Skip the Stack Overflow rabbit holes. Install mkcert, run two commands, and get back to coding.
Your future self—staring at a clean browser address bar with that satisfying lock icon—will thank you.
Ready to eliminate certificate pain forever? Grab mkcert from the official repository and join the thousands of developers who've already upgraded their local development experience.
Found this guide valuable? Share it with your team and save them from certificate hell. Have advanced mkcert patterns or edge cases to discuss? The community around this tool continues to discover powerful workflows—dive in and contribute your own.