mkcert is a simple, zero-config tool for making locally-trusted development certificates. It creates a local Certificate Authority (CA) on your machine, adds it to the system (and optionally Firefox/Chromium and Java) trust stores, and then issues short-lived TLS certificates for any hostname, IP address, email, or URI you supply. The result: green padlocks in browsers, working HTTPS in development, and no more "self-signed cert" red banners — without asking the public web to trust you.
This guide is for developers who want to use mkcert day-to-day. For architecture, full configuration reference, security analysis, and developer internals, see the mkcert Administrator & Developer Guide in the same output directory.
1. Quick Start
Install mkcert with your package manager, install the local CA into your
trust stores, and issue a certificate for localhost — three commands.
Install in 60 seconds (macOS)
brew install mkcert
mkcert -install
mkcert localhost 127.0.0.1 ::1
That generates two files in your current directory:
The certificate is at "./localhost+2.pem" and the key at "./localhost+2-key.pem"
It will expire on 28 July 2028
Wire those two PEM files into whatever HTTPS server you're testing — Caddy,
nginx, Express, Go's http.ListenAndServeTLS, Vite, Next.js dev server, etc.
Open https://localhost in any browser and you will see a valid, trusted
certificate. No flag-overrides, no --insecure, no exception clicks.
Tip
Run
mkcert -installonly once per machine. After that, every certificate you mint withmkcert <host>is automatically trusted by the browsers and system services that use the OS root store, and (if installed) by Firefox and Java. You can re-issue per-project certificates as often as you like.
What mkcert does (and doesn't) do
- Generates a private root CA stored in a per-user directory and adds it to your system, NSS (Firefox/Chromium/Chrome), and Java trust stores.
- Issues leaf certificates valid for exactly 2 years and 3 months for any combination of DNS names, IP addresses, email addresses, and URIs.
- Supports wildcards (
*.example.test), ECDSA keys, client-auth certs, PKCS#12 (.p12/.pfx) bundles, and certificate signing from a CSR. - Does not issue publicly-trusted certificates. The CA mkcert creates is trusted only on your machine. mkcert certificates will not work for production, public websites, or anything outside your dev environment.
Caution
The
rootCA-key.pemmkcert generates is a private key for a root certificate authority that your machine will trust completely. Anyone who obtains this key can issue trusted certificates for any domain, includinggoogle.comor your bank. Never copyrootCA-key.pembetween machines, commit it to source control, or share it. See Section 7 of the Admin Guide for the full security discussion.
2. Installation
mkcert is a single Go binary with no runtime dependencies. The fastest path is your operating system's package manager. Pre-built binaries and a build-from-source option are available for unsupported platforms.
Choose your install method
Pick the row that matches your environment, then run one command.
| Platform | Easiest method | One-liner |
|---|---|---|
| macOS | Homebrew | brew install mkcert |
| macOS (MacPorts) | MacPorts | sudo port selfupdate && sudo port install mkcert |
| Windows | Chocolatey | choco install mkcert |
| Windows | Scoop | scoop bucket add extras && scoop install mkcert |
| Linux | Linuxbrew | brew install mkcert |
| Arch Linux | pacman | sudo pacman -S mkcert |
| Any | Pre-built binary | Download from the releases page (see below) |
| Any | Build from source | git clone … && go build -ldflags … |
Important
macOS users: You also need the NSS tools so mkcert can install the CA into Firefox. Install them with
brew install nss. Without them, Firefox will not pick up your local CA and you will see "this connection is not secure" warnings only in Firefox.
Important
Linux users: To support Firefox and Chromium, install the certutil binary from your distro's NSS tools package. mkcert auto-detects the right command and prints the install instruction if it is missing —
apt install libnss3-toolson Debian/Ubuntu,yum install nss-toolson RHEL family, orzypper install mozilla-nss-toolson openSUSE.
Recommended path: package manager
macOS (Homebrew)
brew install mkcert
brew install nss # required for Firefox trust
macOS (MacPorts)
sudo port selfupdate
sudo port install mkcert
sudo port install nss
Windows (Chocolatey)
choco install mkcert
Windows (Scoop)
scoop bucket add extras
scoop install mkcert
Linux (Homebrew on Linux)
brew install mkcert
If you are not on a distro with a native package, Homebrew on Linux is the
smoothest path. It installs the binary into ~/.linuxbrew/bin (or
/home/linuxbrew/.linuxbrew/bin on shared machines).
Arch Linux
sudo pacman -Syu
sudo pacman -S mkcert
sudo pacman -S nss # for Firefox trust
Fallback: pre-built binary
If your platform isn't listed above, download a pre-built binary from the
GitHub releases page at
github.com/FiloSottile/mkcert/releases,
mark it executable, and put it on your PATH.
# Linux x86_64 example
curl -L "https://dl.filippo.io/mkcert/latest?for=linux/amd64" -o mkcert
chmod +x mkcert
sudo mv mkcert /usr/local/bin/
mkcert -version
Note
Pre-built binaries are published for
linux/amd64,linux/arm,linux/arm64,darwin/amd64,darwin/arm64, andwindows/amd64. Other platforms must build from source.
Last resort: build from source
You need Go 1.18 or newer.
git clone https://github.com/FiloSottile/mkcert
cd mkcert
go build -ldflags "-X main.Version=$(git describe --tags)"
./mkcert -version
The -ldflags "-X main.Version=…" step is what makes mkcert -version
print a real version string instead of (devel).
Warning
Building inside a Go module that is not the mkcert module will leave
mkcert -versionreporting(devel). This is a known Go limitation, not a bug — it is documented in the mkcert source comments. Either build outside any other module, or pass an explicit-X main.Version=…linker flag.
Install the local CA
Whichever method got you the binary, the next step is the same: install the local CA into your trust stores. Do this once per machine.
mkcert -install
Expected output:
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 and/or Chrome/Chromium trust store (requires browser restart)! 🦊
The local CA is now installed in Java's trust store! ☕️
The exact emoji-flagged lines you see depend on which trust stores are detected on your machine. mkcert auto-detects:
- The OS system store (macOS Keychain, Windows root store, Linux
/etc/ssl/...or equivalent). - NSS-based browsers — Firefox, Chrome, and Chromium — when
certutilis on your PATH. - The Java keystore at
$JAVA_HOME/lib/security/cacerts(or$JAVA_HOME/jre/lib/security/cacertsfor older JDKs), whenkeytoolis available.
Important
Restart any open browser after running
mkcert -install. Browsers cache the trust store at startup; without a restart, freshly-issued certificates may still show as untrusted in tabs that were already open.
Verify your install
Confirm mkcert is on your PATH and find out where it stores the CA:
mkcert -version
mkcert -CAROOT
Expected output:
v1.4.4
/home/jane/.local/share/mkcert
The exact -CAROOT location varies by platform — see the platform table in
Section 3.
3. Configuration
mkcert is built to be zero-config. Everything you'd normally need to tune is
exposed as either a CLI flag or one of three environment variables. There
are no config files — nothing in ~/.config, no mkcert.yaml, nothing
to edit. If you want to change behavior, you set an env var or pass a flag.
Environment variables
| Variable | Purpose | Default |
|---|---|---|
CAROOT |
Override the CA storage directory. Useful for keeping multiple parallel CAs (one per project, one for CI, etc.). | Per-platform path (see table below). |
TRUST_STORES |
Comma-separated allow-list of trust stores. Valid entries: system, java, nss. |
All detected stores. |
JAVA_HOME |
Required only for Java trust-store integration. Tells mkcert where to find keytool and cacerts. |
Read from environment. |
The CA storage location, when CAROOT is unset, is computed from the OS
and a small set of standard environment variables.
| Platform | Default CAROOT |
|---|---|
| Windows | %LocalAppData%\mkcert |
| macOS | $HOME/Library/Application Support/mkcert |
| Linux | $XDG_DATA_HOME/mkcert (if set) or $HOME/.local/share/mkcert |
You can always ask mkcert directly:
mkcert -CAROOT
Limit which trust stores get the CA
By default, mkcert -install writes the CA into every trust store it
detects. Set TRUST_STORES to limit that to just the ones you want. The
value is a comma-separated subset of system, java, nss.
# Install only into the OS system store (skip Firefox + Java)
TRUST_STORES=system mkcert -install
# Install only into Firefox/Chromium (skip system + Java)
TRUST_STORES=nss mkcert -install
Tip
The
TRUST_STORESfilter applies to both-installand-uninstall. If you only ever installed intonss, set the same value when you uninstall — otherwise mkcert will quietly skip stores it can't find the CA in, which is harmless but might look confusing.
Run multiple CAs side-by-side
Because every aspect of CA storage is keyed on $CAROOT, you can keep as
many independent CAs as you want by switching directories. This is the
recommended way to keep "personal" and "client work" CAs separate, or to
build a one-off CA for a CI pipeline.
# Personal CA (default)
mkcert example.test
# Client-X CA (separate root, separate trust)
CAROOT=$HOME/.mkcert-clientx mkcert -install
CAROOT=$HOME/.mkcert-clientx mkcert client-x.test
Each CA gets its own rootCA.pem and rootCA-key.pem inside its directory.
4. Core Usage
Most of mkcert's surface area is the leaf-certificate command. Run mkcert with one or more host arguments and it issues a cert. Everything else is trust-store management.
Top-level commands
| Command | What it does |
|---|---|
mkcert -install |
Create the local CA (if missing) and install it into every detected trust store. |
mkcert -uninstall |
Remove the local CA from every trust store. Does not delete the CA on disk. |
mkcert <hosts…> |
Issue a leaf certificate covering the listed hosts. |
mkcert -CAROOT |
Print the directory where the CA is stored. |
mkcert -help |
Print full help, including advanced options. |
mkcert -version |
Print mkcert version and exit. |
Issue a certificate
Pass any combination of DNS names, IP addresses, email addresses, and URIs on the command line. mkcert validates each, normalizes IDN domains to punycode, and emits a single cert covering all of them as Subject Alternative Names (SANs).
mkcert example.com myapp.dev localhost 127.0.0.1 ::1
Expected output:
Created a new certificate valid for the following names 📜
- "example.com"
- "myapp.dev"
- "localhost"
- "127.0.0.1"
- "::1"
The certificate is at "./example.com+4.pem" and the key at "./example.com+4-key.pem" ✅
It will expire on 28 July 2028 🗓
Two files appear in the current directory:
example.com+4.pem— the certificate (PEM-encoded, world-readable, mode 0644).example.com+4-key.pem— the private key (PEM-encoded, mode 0600).
The filename pattern is the first hostname plus +N where N is the count of
extra hosts. Wildcards have * replaced by _wildcard, and colons in IPv6
addresses are replaced by underscores.
Choose your output filenames
If you don't want the auto-generated names, point each output to a custom file with the corresponding flag:
mkcert -cert-file server.crt -key-file server.key example.test
For PKCS#12, use -p12-file:
mkcert -pkcs12 -p12-file bundle.p12 example.test
CLI flag reference
| Flag | Type | Effect |
|---|---|---|
-install |
bool | Install local CA into all detected trust stores. |
-uninstall |
bool | Remove the CA from all detected trust stores. |
-CAROOT |
bool | Print the CAROOT path and exit. |
-help |
bool | Print short + advanced usage and exit. |
-version |
bool | Print the mkcert version and exit. |
-cert-file FILE |
string | Write the leaf certificate to FILE. |
-key-file FILE |
string | Write the leaf private key to FILE. |
-p12-file FILE |
string | Write the PKCS#12 bundle to FILE (requires -pkcs12). |
-client |
bool | Issue a client-authentication cert (sets extKeyUsage clientAuth). |
-ecdsa |
bool | Use an ECDSA P-256 key instead of RSA-2048. |
-pkcs12 |
bool | Output a PKCS#12 (.p12 / .pfx) bundle instead of PEM. |
-csr CSR |
string | Sign the supplied CSR file instead of generating a new key. |
Note
All flags use a single dash (
-install, not--install). This is Go's standardflagpackage style and is the only form mkcert accepts.
Combining flags
Most flags can be combined. The hard rules are:
-installand-uninstallcannot be set together.-CAROOTcannot be combined with-installor-uninstall.-csris exclusive with-pkcs12,-ecdsa, and-client. The only flags allowed alongside-csrare-installand-cert-file.-csrcannot be combined with positional host arguments — the hosts are taken from the CSR itself.
If you violate any of these, mkcert exits with ERROR: … immediately and
issues nothing.
5. Common Tasks
The recipes below cover the day-to-day workflows that nearly every mkcert user hits eventually. Each one lists the goal, what you need first, the exact steps, how to verify, and what to do if it fails.
5.1 Issue a certificate for localhost
Goal: A trusted certificate so https://localhost works in your local
dev server with no browser warnings.
Prerequisites:
- mkcert installed.
mkcert -installalready run on this machine.
Steps:
mkcert localhost 127.0.0.1 ::1
Verify:
ls localhost+2.pem localhost+2-key.pem
openssl x509 -in localhost+2.pem -noout -text | grep -A1 "Subject Alternative Name"
You should see DNS:localhost, IP:127.0.0.1, IP:::1 listed.
If it fails: If you see the local CA is not installed in the system trust store, run mkcert -install and retry. If you don't see a +2
suffix on the filename, you only passed one host — that's fine, the file
will just be named localhost.pem / localhost-key.pem.
5.2 Issue a certificate for a custom dev domain
Goal: A trusted certificate for myapp.test (or any custom dev TLD)
that you point at 127.0.0.1 via /etc/hosts or a local DNS resolver.
Prerequisites:
- mkcert installed and
mkcert -installcomplete. - A line like
127.0.0.1 myapp.testin yourhostsfile, or a wildcard resolver like dnsmasq pointing*.testat loopback.
Steps:
mkcert myapp.test
Verify:
curl -v https://myapp.test/ # once your dev server is running
The * SSL certificate verify ok. line confirms trust.
If it fails: curl: (6) Could not resolve host means the hosts file
or resolver isn't set up — that's a DNS problem, not a mkcert problem.
certificate verify failed: unable to get local issuer certificate means
mkcert -install was not run, or your client (curl) is using its own
bundled CA store rather than the system store. Use --cacert "$(mkcert -CAROOT)/rootCA.pem" for clients that ignore the system store.
5.3 Issue a certificate with multiple SANs (including a wildcard)
Goal: Cover several services from one cert: a wildcard, the apex, localhost, and an IPv4 loopback.
Prerequisites: mkcert -install complete.
Steps:
mkcert "*.dev.local" dev.local localhost 127.0.0.1
Verify:
openssl x509 -in _wildcard.dev.local+3.pem -noout -text | grep "DNS:\|IP:"
You should see all four names.
If it fails: Quote the wildcard. If you see no matches found, that's
your shell expanding * — wrap it in single or double quotes
("*.dev.local").
Warning
X.509 wildcards only match one DNS label.
*.dev.localcoversapp.dev.localbut notapi.staging.dev.local. mkcert prints a reminder when you issue a wildcard cert. Many browsers also reject second-level wildcards like*.local— mkcert prints an explicit warning when it sees one.
5.4 Issue a PKCS#12 bundle for legacy applications
Goal: A .p12 (or .pfx) bundle for IIS, older Java apps, or any
tool that wants the cert and key combined into a single PKCS#12 file.
Prerequisites: mkcert -install complete.
Steps:
mkcert -pkcs12 example.test
Verify:
openssl pkcs12 -in example.test.p12 -info -nokeys -password pass:changeit
If it fails: PKCS#12 bundles are encrypted with the password
changeit — this is a deliberate, hardcoded default for compatibility
with the broad set of tools that expect that password. mkcert prints this
in the output of every PKCS#12 issue. If your tool prompts for a password,
that's the one.
Important
The PKCS#12 password is
changeit— always. It's hardcoded in the source and is intentional: many tools assume that default password. If you need a different password, re-encrypt withopenssl pkcs12 -in bundle.p12 -out new.p12 -nodesthen re-export with the password you want.
5.5 Issue a client-authentication certificate
Goal: A cert with extKeyUsage = clientAuth, suitable for mTLS or
client-cert auth in a browser/curl.
Prerequisites: mkcert -install complete.
Steps:
mkcert -client [email removed]
Verify:
openssl x509 -in 'jane@example.test-client.pem' -noout -text | grep -A1 "Extended Key Usage"
You should see both TLS Web Client Authentication and (because the SAN
is an email) E-mail Protection.
If it fails: mkcert validates each argument as DNS, IP, URI, or email
in turn. If your value isn't recognized as any of those, you get
ERROR: "<value>" is not a valid hostname, IP, URL or email. Quote email
addresses to keep your shell from interpreting @.
5.6 Sign a custom CSR
Goal: Issue a certificate from a CSR generated elsewhere (your CI, your load balancer, your hardware token).
Prerequisites:
- A CSR file in PEM format with type
CERTIFICATE REQUESTorNEW CERTIFICATE REQUEST. mkcert -installcomplete.
Steps:
mkcert -csr request.csr
Verify: mkcert prints the output filename and SANs:
Created a new certificate valid for the following names 📜
- "myapp.test"
The certificate is at "./myapp.test.pem" ✅
If it fails:
failed to read the CSR: unexpected content— the file isn't a PEM block. Re-export.expected CERTIFICATE REQUEST, got …— the PEM type is wrong (oftenCERTIFICATEinstead ofCERTIFICATE REQUEST). Generate a CSR, not a cert.invalid CSR signature— the CSR was tampered with or its signature doesn't match the embedded public key. Regenerate.
Note
When using
-csr, mkcert ignores-pkcs12,-ecdsa, and-client, and you cannot pass extra host arguments — names come from the CSR'ssubjectAltNameextension (or, as a fallback, the CSR's Common Name).
5.7 Find and back up your CA
Goal: Locate the CA on disk so you can back it up, or copy it to another machine you control.
Prerequisites: mkcert installed.
Steps:
mkcert -CAROOT
ls "$(mkcert -CAROOT)"
Verify:
/home/jane/.local/share/mkcert
rootCA-key.pem rootCA.pem
If you want to back the CA up, copy the entire directory to a trusted backup location:
tar -czf mkcert-ca-backup.tar.gz -C "$(mkcert -CAROOT)" .
If it fails: If -CAROOT prints nothing, mkcert couldn't compute a
default. That happens on Linux when both XDG_DATA_HOME and HOME are
empty. Set CAROOT explicitly: export CAROOT=/path/of/your/choice.
Caution
rootCA-key.pemis the private key for a root CA your machine trusts unconditionally. Treat the backup file at least as carefully as you treat your SSH private keys. Encrypt the archive at rest, and never commit it.
5.8 Uninstall the local CA
Goal: Remove the CA from your trust stores when you're done with mkcert (or moving to a different machine).
Prerequisites: None.
Steps:
mkcert -uninstall
Expected output:
The local CA is now uninstalled from the system trust store(s)! 👋
Verify: Re-run mkcert <some host>. mkcert will print
Note: the local CA is not installed in the system trust store along
with whichever stores it could not find the CA in.
If it fails: mkcert -uninstall only removes the CA from trust
stores. The CA files (rootCA.pem, rootCA-key.pem) stay on disk at
-CAROOT. To purge them too:
rm -rf "$(mkcert -CAROOT)"
Do this only if you are certain you don't want any previously-issued certificates to be re-installable.
5.9 Use an ECDSA key instead of RSA
Goal: Smaller, faster keys (P-256 ECDSA) for tools or servers where that matters.
Prerequisites: mkcert -install complete.
Steps:
mkcert -ecdsa example.test
Verify:
openssl x509 -in example.test.pem -noout -text | grep "Public Key Algorithm"
You should see Public Key Algorithm: id-ecPublicKey.
If it fails: ECDSA leaf certs work in every modern browser. If your
specific tool rejects them, drop -ecdsa and use the default RSA-2048.
The CA itself uses RSA-3072 regardless of -ecdsa — that flag only
affects the leaf key.
6. Troubleshooting
When something goes wrong, the first move is almost always to re-run the
failing command and read the actual error. mkcert prints clear ERROR:,
Warning:, and Note: lines and exits non-zero on hard failures.
Diagnostic decision tree
- Is
mkcerton your PATH?mkcert -versionshould print a version. - Is the CA installed?
mkcert -installshould be idempotent — run it. If it prints "already installed", you're good. - Did you restart the browser? Browsers cache trust at startup.
- Is the certificate actually loaded by your server? A trusted cert in a file is useless if your server is using a different one.
Error: failed to find the default CA location, set one as the CAROOT env var
Cause: mkcert couldn't compute a default CAROOT because both
XDG_DATA_HOME and HOME are unset (typically only happens in stripped
container environments or some CI runners).
Solution:
export CAROOT=$HOME/.mkcert
mkcert -install
Prevention: Set CAROOT explicitly in CI configs and ephemeral
containers — never rely on the auto-detected default in those
environments.
Error: can't create new certificates because the CA key (rootCA-key.pem) is missing
Cause: mkcert is running in "keyless mode" — it found rootCA.pem
but not rootCA-key.pem in CAROOT. This happens when you copy only the
public CA cert to a machine and try to issue from it.
Solution: Either issue certs on the machine that has the key, or copy
rootCA-key.pem to the keyless machine. Keyless mode supports -install
but not certificate issuance.
Prevention: When provisioning a new dev machine, copy both
rootCA.pem AND rootCA-key.pem from the source CAROOT.
Error: "<value>" is not a valid hostname, IP, URL or email
Cause: mkcert validates every positional argument as DNS, IP, URL, or email and rejects anything that doesn't match. Common causes:
- A trailing comma or space inside what you thought was one hostname.
- A hostname with characters mkcert's regex doesn't allow (only
0-9a-z._-and an optional leading*.). - A URL that's missing a scheme (
example.com/path— no scheme means it's parsed as a hostname, and/pathmakes it invalid).
Solution: Quote each host, drop trailing punctuation, and lowercase
everything. For URIs, include the scheme: spiffe://trust-domain/foo.
Prevention: Echo your command back before running it — trailing characters are easy to miss.
Error: no Firefox and/or Chrome/Chromium security databases found
Cause: mkcert searches a fixed list of NSS database paths
(~/.pki/nssdb, ~/snap/chromium/.../nssdb, /etc/pki/nssdb,
plus Firefox profile directories). If none exist, you get this error.
This is the situation tracked by issue
#120.
Solution:
- Open Firefox or Chromium at least once. NSS databases are created lazily on first run.
- Confirm the database exists:
ls ~/.pki/nssdb(Chromium) or check your Firefox profile dir. - Re-run
mkcert -install.
Prevention: On a fresh user account, start the browsers once before
running mkcert -install.
Error: Firefox on macOS still shows "Not Secure"
Cause: Several open issues track this — #326,
#370, and
#662. The common root
causes are: (a) the NSS tools aren't installed (brew install nss was
skipped); (b) Firefox is using a custom profile directory that mkcert
doesn't search (issue
#521); (c) Firefox
Developer Edition uses a separate trust DB.
Solution:
brew install nssand re-runmkcert -install.- Restart Firefox completely (not just the window — quit the app).
- If you use a custom profile, copy
rootCA.pemand import it manually via Firefox → Settings → Privacy & Security → View Certificates → Authorities → Import.
Prevention: Stick to the default Firefox profile if you want mkcert to manage trust automatically.
Error: SSL_ERROR_RX_RECORD_TOO_LONG in Firefox
Cause: Tracked in issue #361. This is almost always a server-side misconfiguration: your dev server is speaking plain HTTP on the port Firefox is connecting to as HTTPS. mkcert is not at fault — it's a wiring problem.
Solution: Confirm your dev server is actually listening for TLS on
the port you're hitting. For Vite, that's server.https = true; for
Express, https.createServer({key, cert}, app); for nginx,
ssl on; ssl_certificate …; ssl_certificate_key …;.
Prevention: When wiring up a new dev server, hit it once with
curl -v https://localhost:PORT first — curl errors are clearer than
browser ones for TLS-vs-HTTP confusion.
Error: "sudo" is not available, and mkcert is not running as root
Cause: On Linux/macOS, mkcert needs root to update the system trust
store. It uses sudo by default; if sudo isn't on your PATH and you
aren't already root, the install of the system store will be skipped or
will fail.
Solution: Either run mkcert as root (su -; mkcert -install) or
install sudo (apt install sudo, etc.).
Prevention: Don't run mkcert in stripped containers without sudo —
use TRUST_STORES=nss mkcert -install if you only need browser trust.
Error: PKCS#12 won't import — wrong password
Cause: The PKCS#12 export password is hardcoded to changeit.
If your tool is prompting and changeit doesn't work, the file is
corrupted, not the password.
Solution: Re-issue the bundle: mkcert -pkcs12 -p12-file new.p12 example.test. Use the changeit password to import.
Prevention: Save the bundle straight to where it's needed; don't roundtrip through scp/email/etc., which can corrupt binary files if a client treats them as text.
Error: Cert is rejected by Traefik / cert-manager / your tool
Cause: Tracked in issue #646 for Traefik, #350 for cert-manager comparisons. mkcert certs are short-lived (≈2y3m) and are signed by a CA your tool may not trust by default. Tools running inside containers do not see your host's trust store.
Solution: Mount the CA into the container at the right path:
docker run -v "$(mkcert -CAROOT)/rootCA.pem:/etc/ssl/certs/mkcert-rootCA.pem" …
or copy it into the container image during build.
Prevention: When containerizing your dev stack, treat the mkcert root CA as a build-time secret/asset and mount it explicitly.
Note: macOS 26.1 — root certificate no longer applicable for leaf certs
Cause: Tracked in issue #651. Newer macOS releases tightened root-cert acceptance rules.
Solution: Watch the upstream issue. As of commit 1c1dc4e, no
mitigation has shipped in mkcert itself. Workaround: re-issue with a
shorter validity if your tool requires it, or pin the root through your
app rather than the OS keychain.
Prevention: None — track the issue.
7. FAQ
Q: Where does mkcert store the CA?
In a per-user directory determined by your OS. On macOS it's
$HOME/Library/Application Support/mkcert; on Windows, %LocalAppData%\mkcert;
on Linux, $XDG_DATA_HOME/mkcert or $HOME/.local/share/mkcert. Override
this with the CAROOT environment variable. To see the active path:
mkcert -CAROOT
Q: How long are mkcert certificates valid for?
Leaf certificates are valid for 2 years and 3 months. The CA itself is valid for 10 years. macOS and iOS reject leaf certs valid for longer than 825 days, so mkcert's 2y3m is the safe ceiling.
Q: Can I use mkcert in production?
No. The CA mkcert creates is trusted only on machines where you've run
mkcert -install. Anyone else hitting your service will see a "not
trusted" error. For production use Let's Encrypt or a commercial CA. See
the Admin Guide Section 7 for the full security discussion.
Q: Why doesn't mkcert -version print a real version when I built from source?
Go embeds the version of the main module via debug.BuildInfo, but if you
build mkcert as part of a different module (or directly from a Git clone
without any module context), Go reports (devel). Build with
go build -ldflags "-X main.Version=$(git describe --tags)" to bake in a
real version. This is documented in mkcert's source comments referencing
golang/go#29814 and
golang/go#29228.
Q: How do I share my CA between machines I own?
Copy the entire CAROOT directory (both rootCA.pem and rootCA-key.pem)
to the same path on the other machine, then run mkcert -install there.
Treat the copy operation like sharing an SSH private key — encrypted
transport, no clouds you don't control. See Section 5.7.
Q: Can I customize the root CA's name (Organization, Common Name, etc.)?
Not via flags. The CA's Subject is hardcoded to O=mkcert development CA, OU=<user>@<host>, CN=mkcert <user>@<host>. Issue
#229 tracks this as a
feature request. If you must customize, build mkcert from source with a
patched newCA() in cert.go.
Q: Does mkcert support IPv6?
Yes. Pass IPv6 addresses on the command line just like IPv4:
mkcert localhost ::1 fe80::1
The output filename uses underscores in place of colons.
Q: Why is the PKCS#12 password changeit?
It's the de facto standard default for keystores (Java's cacerts uses it,
many tools assume it). mkcert hardcodes it for compatibility with the
broadest set of tools. There is no flag to change it; re-encrypt with
openssl if you need a different password.
Q: Can I limit which trust stores mkcert touches?
Yes — set TRUST_STORES to a comma-separated subset of system, nss,
java. Example: TRUST_STORES=system mkcert -install only writes to the
OS root store.
Q: How do I issue a cert with a wildcard?
Quote it so your shell doesn't expand the asterisk:
mkcert "*.example.test"
The output filename will be _wildcard.example.test.pem. Wildcards only
match one DNS label (the asterisk does not match dots), and many browsers
reject second-level wildcards like *.test — mkcert prints a warning
when it sees one. See Section 5.3.
Q: Can I use mkcert without installing the CA into the system store?
Yes — skip mkcert -install, and use clients that take an explicit CA
file. With curl --cacert "$(mkcert -CAROOT)/rootCA.pem" you can verify
mkcert-issued certs without touching any trust store. This is also useful
in CI: ship rootCA.pem as a build artifact, point your test clients at
it.
Q: Does mkcert work on Apple Silicon / ARM Linux?
Yes — pre-built binaries exist for darwin/arm64 and linux/arm64. See
the GitHub releases page. For other ARM variants (e.g. armv5), build from
source with the appropriate GOARCH. Issue
#652 discusses
cross-arch support more broadly.
Q: How do I rotate or regenerate the CA?
Run mkcert -uninstall, then rm -rf "$(mkcert -CAROOT)", then
mkcert -install. mkcert will create a fresh CA. Every previously
issued leaf certificate becomes invalid the moment you do this — they
were signed by a CA that no longer exists in any trust store. Re-issue
the certs you still need.
Q: Is mkcert affected by recent macOS / iOS root-cert restrictions?
Some are tracked in upstream issues — see issue #651 for the macOS 26.1 changes and #343 for general expiration discussion. mkcert already targets the 825-day ceiling Apple platforms enforce, so most users are unaffected.