In Local Development, sometimes we often need to emulate an https environment, for example, PWA applications that require https access. In the traditional solution, we need to use self-signed certificate, and then use self-signed certificate in http server. Since self-signed certificates are not trusted by browsers, to solve the browser trust problem we need to add the CA certificate used by self-signed certificates to the trusted CA certificate of the system or browser to circumvent this problem.

Previously these steps required a series of tedious openssl commands to generate, although there are scripted solutions to help us simplify entering these commands. But it still feels less friendly for local development and a bit cumbersome. In this article, we will introduce a simpler and more friendly way to generate local https certificates and trust self-signed CAs - mkcert.

mkcert Introduction

mkcert is a small program written in go language to generate local self-signed books, with cross-platform, easy to use, support for multiple domains, automatic trust CA and a series of convenient features for local development when quickly create https environment to use.

Installation is also very simple, due to the static compilation of go language and cross-platform features, the official platform to provide pre-compiled version, directly downloaded to the local, give executable permissions (Linux/Unix need) can be. Download at: https://github.com/FiloSottile/mkcert/releases/latest

In addition, mkcert has been pushed to Homebrew, MacPorts, Linuxbrew, Chocolatey, Scoop and other package management platforms, or you can install them directly with the corresponding package management platform. For example:

1
2
brew install mkcert  # Homebrew/Linuxbrew
choco install mkcert  # Chocolatey

After successful installation, you should be able to use the mkcert command:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
PS C:\Users\abcfy\projects> mkcert
Using the local CA at "C:\Users\abcfy\AppData\Local\mkcert"Usage of mkcert:

        $ mkcert -install
        Install the local CA in the system trust store.

        $ mkcert example.org
        Generate "example.org.pem" and "example.org-key.pem".

        $ mkcert example.com myapp.dev localhost 127.0.0.1 ::1
        Generate "example.com+4.pem" and "example.com+4-key.pem".

        $ mkcert "*.example.it"
        Generate "_wildcard.example.it.pem" and "_wildcard.example.it-key.pem".

        $ mkcert -uninstall
        Uninstall the local CA (but do not delete it).

For more options, run "mkcert -help".

mkcert Basic Usage

From the help output above, mkcert already gives a basic workflow that circumvents the complicated openssl command, and a few simple parameters can generate a local trusted https certificate. For more detailed usage, just look at the official documentation.

Add CA certificate to local trusted CA

1
2
$ mkcert -install
Using the local CA at "C:\Users\abcfy\AppData\Local\mkcert"

This simple command helps us to add the root certificate used by mkcert to the local trusted CA, so that certificates issued by this CA will be trusted in local.

You can find this certificate in the list of trusted CAs in Windows:

The same can be found in the list of certificates for MacOS:

Similarly, the effect is similar on Linux systems, so we won’t demonstrate it here.

Generate self-signed certificate

The command to generate a self-signed certificate is very simple:

1
mkcert domain1 [domain2 [...]]

Directly follow multiple domains or ip’s to be issued, e.g. issue a certificate for local access only (accessible via 127.0.0.1 and localhost, and ipv6 address::1)

1
2
3
4
5
6
7
8
9
 mkcert localhost 127.0.0.1 ::1
Using the local CA at "C:\Users\abcfy\AppData\Local\mkcert"
Created a new certificate valid for the following names 📜
 - "localhost"
 - "127.0.0.1"
 - "::1"

The certificate is at "./localhost+2.pem" and the key at "./localhost+2-key.pem"

Through the output, we can see that the localhost+2.pem certificate file and localhost+2-key.pem private key file are successfully generated, just use these two files on the web server.

Using the generated certificate file

The default generated certificate format is PEM (Privacy Enhanced Mail) format, which can be used by any program that supports PEM format certificates. For example, the common Apache or Nginx, etc. Here we use python comes with SimpleHttpServer to demonstrate the effect of this certificate (code reference from: https://gist.github.com/RichardBronosky/644cdfea681518403f5409fa16823c1f):

python2 version (the version that comes with MacOS):

1
2
3
4
5
6
7
8
#!/usr/bin/env python2

import BaseHTTPServer, SimpleHTTPServer
import ssl

httpd = BaseHTTPServer.HTTPServer(('0.0.0.0', 443), SimpleHTTPServer.SimpleHTTPRequestHandler)
httpd.socket = ssl.wrap_socket(httpd.socket, certfile='./localhost+2.pem', keyfile='./localhost+2-key.pem', server_side=True, ssl_version=ssl.PROTOCOL_TLSv1_2)
httpd.serve_forever()

python3 version:

1
2
3
4
5
6
7
8
#!/usr/bin/env python3

import http.server
import ssl

httpd = http.server.HTTPServer(('0.0.0.0', 443), http.server.SimpleHTTPRequestHandler)
httpd.socket = ssl.wrap_socket(httpd.socket, certfile='./localhost+2.pem', keyfile='./localhost+2-key.pem', server_side=True, ssl_version=ssl.PROTOCOL_TLSv1_2)
httpd.serve_forever()

Just run it with python simple-https-server.py (note that binding to port 443 on Linux/Unix requires root privileges, you may need to use sudo to raise privileges)

For use within a local area network

Sometimes we need to test https applications on the LAN, and this environment may not be external, so we cannot use a free certificate solution like Let's encrypt to issue a trusted certificate to the LAN, and Let's encrypt itself does not support authentication Ip.

First, let’s recall the three elements of a trusted certificate:

  • Issued by a trusted CA
  • The access address matches the certificate authentication address
  • The certificate is valid

If we expect our self-signed certificate to be used on the LAN, all three of these conditions need to be met. Obviously the self-signed certificate must meet the certificate within the validity period, then the last two need to be ensured. The certificate we issue must match the address bar of the browser, such as the IP or domain name of the LAN, and we also need to trust the CA.

Let’s reissue the certificate and add the local LAN ip authentication:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
 mkcert localhost 127.0.0.1 ::1 192.168.31.170
Using the local CA at "C:\Users\abcfy\AppData\Local\mkcert"
Created a new certificate valid for the following names 📜
 - "localhost"
 - "127.0.0.1"
 - "::1"
 - "192.168.31.170"

The certificate is at "./localhost+3.pem" and the key at "./localhost+3-key.pem"

Verify again and find that local access using https://192.168.31.170 is also trusted. Then we need to issue the CA certificate to other users in the LAN.

1
2
 mkcert -CAROOT
C:\Users\abcfy\AppData\Local\mkcert

Use mkcert -CAROOT command to list the storage path of CA certificate

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
 ls $(mkcert -CAROOT)


    目录: C:\Users\abcfy\AppData\Local\mkcert


Mode                LastWriteTime         Length Name
----                -------------         ------ ----
-a----  2019-04-09-星期二  上午 1           2484 rootCA-key.pem
                             2:16
-a----  2019-04-09-星期二  上午 1           1651 rootCA.pem
                             2:16

You can see there are two files rootCA-key.pem and rootCA.pem under CA path, users need to trust the file rootCA.pem. Make a copy of rootCA.pem and name it rootCA.crt (because windows does not recognize the pem extension and Ubuntu does not treat the pem extension as CA certificate file), distribute the rootCA.crt file to other users and import it manually.

To import a certificate into windows, double-click the file and import the certificate into a trusted root certificate authority in the Certificate Import Wizard:

MacOS does the same thing, again choosing to import the CA certificate to a trusted root certificate authority.

For Ubuntu, you can put the certificate file (must have crt suffix) into /usr/local/share/ca-certificates/ and then execute sudo update-ca-certificates.

For Android and IOS trust CA certificates, refer to the official documentation.

Other computers on the LAN will be able to access https without alarm. I tested the results on another virtual machine Ubuntu using curl:

1
2
3
4
5
6
$ curl -I https://192.168.31.170
HTTP/1.0 200 OK
Server: SimpleHTTP/0.6 Python/3.6.8
Date: Tue, 09 Apr 2019 05:22:12 GMT
Content-type: text/html; charset=utf-8
Content-Length: 1794

No warning, plus the -v parameter output will also tell that the certificate is trusted.

Some other advanced uses

The above demonstrates some of the most basic uses of mkcert, which are very simple. If we open mkcert --help and read the help, we can find many more advanced uses.

For example, -cert-file FILE, -key-file FILE, -p12-file FILE can define the output certificate file name.

-client can generate client-side authentication certificates for two-way SSL authentication.

The -pkcs12 command can generate certificates in PKCS12 format. java programs usually do not support certificates in PEM format, but they do support certificates in PKCS12 format. With this program, we can easily generate PKCS12 format certificates for Java programs directly, so we will not demonstrate it here.

Other advanced usage will not be introduced, you can discover it according to your actual needs and scenarios if you are interested.

Summary

This article we introduced a good little tool mkcert, simplify the complexity of our local build https environment, no need to operate the complicated openssl to achieve self-signed certificates, this small program can help us self-signed certificates, in local use It will also automatically trust the CA, very convenient.


Reference https://blog.dteam.top/posts/2019-04/%E6%9C%AC%E5%9C%B0https%E5%BF%AB%E9%80%9F%E8%A7%A3%E5%86%B3%E6%96%B9%E6%A1%88mkcert.html