Open-source project
FiloSottile/mkcert avatar
FiloSottile/mkcert

mkcert installs the CA but never configures your server, and its docs have drifted from go.mod

GitHub describes it as A simple zero-config tool to make locally trusted development certificates with any names you'd like.. The repository metadata lists Go as its primary language. The metadata lists the BSD-3-Clause license. This article stays within the project description and details documented in the GitHub repository README.

59,712 stars3,140 forksGoBSD-3-Clause

At a glance

What is it?
mkcert is a small Go tool that creates a local certificate authority and installs it into your trust stores, so development hosts stop throwing trust errors. It leaves the server wiring, the mobile install, and the Node integration to you, and it has not been released since 2022.
Who is it for?
mkcert earns its place when you are tired of trust errors on localhost and on names like example.test, and you want a local CA handled in one command instead of hand-rolled openssl steps. It is the wrong tool if you need certificates that are valid anywhere, if you need your server configured for you, or if you expect the trust story on mobile and in Node to be automatic.
Can I use it commercially?
Yes. BSD-3-Clause is a permissive licence: you can use, modify and sell software built on it, as long as you keep its copyright and licence notices.
Is it still maintained?
Probably not. The repository last received commits 25 months ago, on August 13, 2024.
What is it written in?
Mainly Go, according to GitHub's language statistics.

Answers come from the project's GitHub data, last synced on September 29, 2026, and from our analysis. They are not legal advice.

Editorial analysis

mkcert installs the CA and stops there

The scope of the tool is stated plainly, and it is worth reading before you install it. mkcert automatically creates and installs a local CA in the system root store, and generates locally-trusted certificates. It then does not configure servers to use those certificates, because that part is left up to you. So the run that prints the paths to a .pem file is the end of the tool's work, not the end of your task. What mkcert cannot do is point your dev server, reverse proxy, or application framework at the certificate. You still have to read the two filenames it hands you and wire them into whatever runs your code. If you expected a one-command fix for a browser warning, expect instead one command for the trust half and a manual step for the serving half.

rootCA-key.pem is the file that must never leave your machine

The project attaches a warning to the file it generates automatically: rootCA-key.pem gives complete power to intercept secure requests from your machine, so do not share it. The certificate itself is a different matter. Installing into a trust store does not require the CA key, which means you can move the CA to another machine and still install it there. The procedure is to look for rootCA.pem in the folder printed by mkcert -CAROOT, copy that file to the other machine, set $CAROOT to its directory, and run mkcert -install. The consequence for a reader is a clean split: the .pem certificate is a shareable public artifact, the -key.pem is the whole security boundary. Copying the wrong one of the two files, or attaching rootCA-key.pem to a bug report, hands someone else interception of everything your machine trusts.

Node does not read the system trust store, so it needs its own hook

The trust stores mkcert writes to are the operating system ones plus Firefox, Chrome, and Chromium, and Java when JAVA_HOME is set. Node sits outside all of that. Node does not use the system root store, so it will not accept mkcert certificates automatically, and the fix is an environment variable rather than another trust install:

bash
export NODE_EXTRA_CA_CERTS="$(mkcert -CAROOT)/rootCA.pem"

What this exposes is that the trust story is not one switch. Every runtime that keeps its own certificate list instead of reading the system store needs a separate instruction, and the Node case is only the one documented. A reader whose stack is Node plus a browser therefore has two distinct trust configurations, and a setup script that only runs mkcert -install will leave the browser happy and the server-side fetch failing, which is a confusing split to debug if you do not know to look for it.

Firefox needs certutil, and Linux needs one of three trust commands

Firefox is supported on macOS and Linux only, and on Linux it depends on a helper you install yourself, certutil. The distribution package names vary:

bash
sudo apt install libnss3-tools

with yum, pacman, and zypper equivalents for other families. The system store on Linux is not universal either. mkcert supports Linux variants that provide update-ca-trust on Fedora, RHEL, and CentOS, update-ca-certificates on Ubuntu, Debian, OpenSUSE, and SLES, or trust on Arch. What mkcert cannot do is reach a distribution that offers none of those three commands, and on such a system the system-store path silently does not apply. You can also narrow the blast radius with the TRUST_STORES environment variable, set to a comma-separated list drawn from system, java, and nss, where nss includes Firefox. Installing into fewer stores is the option to reach for on a machine where you do not want a local CA trusted more widely than the task needs.

Options must come before the domain list, and -csr conflicts with most of them

The advanced flags are small but positional, which is the most likely thing to trip you up. You must place these options before the domain names list:

code
	-cert-file FILE, -key-file FILE, -p12-file FILE
	    Customize the output paths.

	-client
	    Generate a certificate for client authentication.

	-ecdsa
	    Generate a certificate with an ECDSA key.

	-pkcs12
	    Generate a ".p12" PKCS #12 file, also know as a ".pfx" file,
	    containing certificate and key for legacy applications.

	-csr CSR
	    Generate a certificate based on the supplied CSR. Conflicts with
	    all other flags and arguments except -install and -cert-file.

The worked example keeps them in front:

code
mkcert -key-file key.pem -cert-file cert.pem example.com *.example.com

The -csr mode is the outlier, because it conflicts with every other flag and argument apart from -install and -cert-file. So you cannot combine a supplied CSR with -client, -ecdsa, or -pkcs12. There is also a quiet behavior worth knowing: if one of the names you pass is an email address, mkcert generates an S/MIME certificate instead of a TLS one.

The README Go version disagrees with go.mod

Building from source is offered on both Linux and Windows, and the stated toolchain floors are low. The Linux instructions say Go 1.13 or later and the Windows instructions say Go 1.10 or later. The module definition disagrees with both. go.mod declares the module as filippo.io/mkcert and sets go 1.18, so a toolchain older than 1.18 is what the build actually asks for, and it pulls in golang.org/x/net, howett.net/plist, and software.sslmate.com/src/go-pkcs12 at v0.2.0. What the documentation cannot do is keep the two in step, because they live in different files and only one of them is enforced by the toolchain. If you follow the README's stated floor and pick a Go older than 1.18, the build is the thing that fails, not the documentation. Read go.mod as the real requirement.

The newest tag is more than two years older than the last commit

The release history is short and the newest entry is old. v1.4.4, described as Firefox Snap support for Ubuntu 22.04, is dated 2022-04-26. Before it, v1.4.3 cleaned up EKUs on 2020-11-25, and v1.4.2 was released on 2020-10-26 under the name It has been a while. The repository was last pushed to on 2024-08-13. What that gap means for a reader is that the default branch carries work that has never been tagged, so building from source gives you an artifact that is not the last release, and pinning to v1.4.4 gives you something older than the source you just read. It also means the project is not under active development, so a new operating system release, a new browser, or a changed trust command can move past what these files know about, and the README will not be the thing that warns you.

Mobile trust is a manual profile install, and Android only works in a development build

Getting a phone to trust the CA is the least automated part of the whole flow. For certificates to be trusted on mobile devices you have to install the root CA, which is the rootCA.pem file in the folder printed by mkcert -CAROOT, and mkcert has no command that pushes it to a handset. On iOS you can use AirDrop, email the CA to yourself, or serve it from an HTTP server, and after opening it you install the profile in Settings under Profile Downloaded and then enable full trust in it. On Android you install the CA and then enable user roots in the development build of your app. What this cannot do is reach a release build, because the user-roots switch exists only in development builds. A reader testing on a real phone is therefore doing device setup by hand for every device, and a reader testing against shipped app builds is not going to get a trusted local CA at all.

Editorial conclusion

mkcert earns its place when you are tired of trust errors on localhost and on names like example.test, and you want a local CA handled in one command instead of hand-rolled openssl steps. It is the wrong tool if you need certificates that are valid anywhere, if you need your server configured for you, or if you expect the trust story on mobile and in Node to be automatic. Before you rely on it, confirm the root CA key never leaves your machine, check whether your Linux distribution offers one of the trust commands it knows, and build from source only after reading go.mod, which asks for a newer Go than the README claims.

Frequently asked questions

What is mkcert used for?

mkcert is a zero-config tool for making locally-trusted development certificates with any names you want. It automatically creates and installs a local CA in the system root store and generates locally-trusted certificates, so hosts like localhost, 127.0.0.1, and example.test stop throwing trust errors.

Is MKCERT trustworthy?

The project warns that the automatically generated rootCA-key.pem gives complete power to intercept secure requests from your machine and must not be shared, and that mkcert is meant for development rather than production, so it should not be used on end users' machines. The shareable file is rootCA.pem, not the key.

Where does MKCERT put the certificate?

The CA certificate and its key are stored in an application data folder inside the user home, and the location is printed by mkcert -CAROOT. You can set the $CAROOT environment variable to manage separate CAs. Certificates you request are written as .pem files in the working directory, with the key in a matching -key.pem file.

how to install mkcert on ubuntu

On Linux you first install certutil, which on Ubuntu and Debian is the libnss3-tools package. After that you can install mkcert through Homebrew on Linux, build it from source with Go, or download a pre-built binary. Arch users can install it from the official Arch repository with sudo pacman -Syu mkcert.

how to use mkcert

Run mkcert -install once to create and install the local CA into the system and Firefox trust stores, then run mkcert followed by the names you want a certificate for. Flags such as -cert-file, -key-file, -ecdsa, and -pkcs12 must be placed before the domain names list.

Official sources

  1. Official documentation
  2. Official README
  3. Project repository
  4. Release notes
Add this badge to your README

If you maintain this project, the badge below links readers to this analysis and shows its maintenance status from the daily GitHub snapshot. Paste the markdown into your README; add ?metric=license or ?metric=stars to the image URL for a different field.

Add this badge to your README

markdown
[![Hysen Labs](https://hysenlabs.com/badge/filosottile-mkcert.svg)](https://hysenlabs.com/projects/filosottile-mkcert)