Local TLS with `mkcert`
Overview of use of `mkcert` for TLS with a local CA.
Local TLS with mkcert
When it comes to GoodMem, we consider TLS at the service boundary a baseline responsibility, not an optional enhancement.
While users can always opt into plaintext with --tls-disabled and set up their own service boundary, we want to make default, TLS-enabled operation as frictionless as possible.
GoodMem does support self-signed certificates today, but those come with their own problems in browsers and applications that treat them as low trust.
With the CLI tool mkcert, users can host a local certificate authority (CA) to develop within TLS without those problems.
GoodMem with mkcert
mkcert is a vetted tool for making locally-trusted certificates for development environments.
If you've already got mkcert installed on your machine, or you'll be using another similar tool, feel free to skip ahead.
Otherwise, let's get started.
Installing mkcert
mkcert may be installed via package managers, pre-built binaries, or building from source.
See its documentation for more details: https://github.com/FiloSottile/mkcert
Running mkcert
Once installed, mkcert needs to create a local certificate authority (CA) like so:
$ mkcert -installOn success, you should see a message like this:
Created a new local CA 💥
The local CA is now installed in the system trust store! ⚡️Then creating the local certificates is as simple as:
$ mkcert goodmem.test localhost 127.0.0.1 ::1On success, you should see a message like the following:
Created a new certificate valid for the following names 📜
- "goodmem.test"
- "localhost"
- "127.0.0.1"
- "::1"
The certificate is at "./goodmem.test+3.pem" and the key at "./goodmem.test+3-key.pem" ✅Among the options provided by mkcert,
you may want to use the -cert-file FILE and -key-file FILE flags. For example:
$ mkcert -key-file secret/file/here/key.pem -cert-file secret/file/there/cert.pem goodmem.testRunning goodmem with TLS Certificates
At this point, you now have two options to tell GoodMem about your new certificates. You can pass these either as CLI flags or as environment variables, as described in TLS Configuration. In both cases, the file options are paired: passing one file requires you to pass the other as well.
Environment variables
As is idiomatic with Docker containers, the GoodMem Docker image expects its configuration variables to be passed in via environment variables. In particular, the TLS files should be specified as:
| Environment variable | Description |
|---|---|
GOODMEM_TLS_CERT_FILE | PEM certificate/chain for user-supplied TLS (requires GOODMEM_TLS_KEY_FILE). |
GOODMEM_TLS_KEY_FILE | PEM private key for user-supplied TLS (GOODMEM_TLS_CERT_FILE`). |
GOODMEM_TLS_TRUST_CERT_FILE | Reserved for future client-auth support; currently unused for inbound TLS. |
CLI Flags
Alternatively, you may pass CLI flags to the GoodMem server directly:
| Server flag | Description |
|---|---|
--tls-cert-file | PEM certificate/chain for user-supplied TLS (requires --tls-key-file). |
--tls-key-file | PEM private key for user-supplied TLS (requires --tls-cert-file). |
--tls-trust-cert-file | Reserved for future client-auth support; currently unused for inbound TLS. |
Validation
And that's it! You now have everything you need to run GoodMem with CA-signed certificates. You may validate your server is using the certificates with the following:
$ curl -v --cacert path/to/your/goodmem.pem --cert-type PEM https://127.0.0.1:8081/readyz
$ # OR
$ curl -v --cacert path/to/your/goodmem.pem --cert-type PEM https://localhost:8081/readyzYou should see a --verbose response with the TLS handshake and more details:
Trying 127.0.0.1:8081...
* Connected to localhost (127.0.0.1) port 8081 (#0)
* ALPN, offering h2
* ALPN, offering http/1.1
* CAfile: ./goodmem.pem
* CApath: /etc/ssl/certs
* ...
* SSL connection using TLSv1.3 / TLS_AES_256_GCM_SHA384
* ALPN, server did not agree to a protocol
* Server certificate:
* subject: O=mkcert development certificate; OU=root@[...]
* start date: Jan 1 00:00:00 2026 GMT
* expire date: Apr 1 00:00:00 2028 GMT
* subjectAltName: host "localhost" matched cert's "localhost"
* issuer: O=mkcert development CA; OU=root@[...]; CN=mkcert root@[...]
* SSL certificate verify ok.
* TLSv1.2 (OUT), TLS header, Supplemental data (23):
> GET /readyz HTTP/1.1
> Host: localhost:8081
> User-Agent: curl/7.81.0
> Accept: */*
>
* TLSv1.2 (IN), TLS header, Supplemental data (23):
* Mark bundle as not supporting multiuse
< HTTP/1.1 200 OK
< Content-Type: application/json
< Content-Length: 30
< Server: Jetty(11.0.26)
<
* Connection #0 to host localhost left intact
{"ready":true,"state":"READY"}Note: this would not work without a local CA because
"no one can get a universally valid certificate for localhost".
With mkcert or similar tools, such a local CA can be easily set up on your developer's machine to more closely reflect the CA your production deployment relies on.
Happy hacking! :)