🚀 Executive Summary

TL;DR: Local HTTPS trust issues, such as `NET::ERR_CERT_AUTHORITY_INVALID`, occur because browsers do not inherently trust self-signed certificates used in local development. This guide explains how to establish a local Certificate Authority (CA) and issue trusted certificates, enabling seamless HTTPS functionality on your machine using either manual OpenSSL commands or the automated `mkcert` tool.

🎯 Key Takeaways

  • Modern browsers strictly require SSL/TLS certificates to include Subject Alternative Names (SANs) for `localhost`, specific IP addresses, or custom domains to be considered valid.
  • To achieve local HTTPS trust, you must create your own Root Certificate Authority (CA), generate its public certificate (`.pem`), and explicitly import it into your operating system’s trust store (e.g., Keychain Access on macOS, `certlm.msc` on Windows, or `/usr/local/share/ca-certificates` on Linux).
  • Tools like `mkcert` significantly simplify the process of setting up a local CA and generating trusted certificates by automating the complex OpenSSL commands and system trust store integrations.

SSL/TLS explained (newbie-friendly): certificates, CA chain of trust, and making HTTPS work locally with OpenSSL

Demystify local SSL/TLS certificate errors for good. This guide explains the “why” behind HTTPS trust issues and provides actionable OpenSSL and mkcert solutions for a seamless local development experience.

Wrestling with HTTPS Locally: Your Guide to Slaying the SSL Dragon

I still remember it. It was 2 AM, the night before a major demo, and our brand-new microservice, running perfectly on my machine, refused to talk to the frontend. The culprit? A cryptic NET::ERR_CERT_AUTHORITY_INVALID error in the browser console. I knew the data was there, I knew the API worked, but that little red padlock was holding our entire demo hostage. It’s a rite of passage for every developer, that moment you realize “It’s just my local machine” doesn’t mean the rules of the internet suddenly don’t apply. That night taught me a valuable lesson: understanding how TLS/SSL works, even just for local development, isn’t academic—it’s a critical, time-saving skill.

The “Why”: It’s All About Trust (Or Lack Thereof)

So what’s actually happening? In simple terms, your browser and operating system have a built-in list of bouncers they trust, called Root Certificate Authorities (CAs). When you visit https://google.com, Google presents an ID (its SSL certificate) that’s been signed by one of these trusted bouncers. Your browser checks the signature, sees it’s on the guest list, and lets you in with a green padlock.

When you create a “self-signed” certificate with a quick OpenSSL command, you’re essentially showing up with a homemade ID. Your browser takes one look at it, doesn’t recognize the signature, and slams the door in your face with a security warning. It has no idea who you are or if it can trust you. The goal for local development is to become our own bouncer—to create our own little Certificate Authority and tell our machine, “Hey, this guy? He’s with me. Trust him.”

Okay, Darian. Enough Theory. How Do We Fix It?

I’ve seen junior engineers (and seniors, let’s be honest) waste hours on this. Let’s break down the solutions from the quick and dirty to the “do it right once and forget it” approach.

Solution 1: The “I Don’t Care, Just Make It Work” Quick Fix

This is the classic “click ‘Advanced’ and ‘Proceed to unsafe’” in Chrome. For command-line tools like curl, it’s the -k or --insecure flag.

# This tells curl to ignore certificate validation entirely
curl -k https://localhost:8443/api/v1/health

When to use it: When you need to check a single endpoint right now and you don’t care about security. You’re just checking if the server is up or if it’s returning the JSON you expect.

Warning: This is a terrible habit. It trains you to ignore security warnings and is useless for complex scenarios where your frontend code (running in the browser) needs to make API calls, or one local service needs to call another. Do not let this become your default.

Solution 2: The “Do It Right” Local CA Method with OpenSSL

This is the manual but powerful way. We will become our own CA, tell our computer to trust it, and then issue a “valid” certificate for our local service. This is the foundation for understanding how everything works.

Step 1: Create Your Root Authority

First, we generate a private key and a root certificate for our new authority. This is the master key to our kingdom. Guard it well (or, you know, just keep it in your project’s `dev/certs` folder).

# Generate the Root CA private key
openssl genrsa -out myLocalCA.key 2048

# Generate the Root CA certificate (we'll self-sign it)
openssl req -x509 -new -nodes -key myLocalCA.key -sha256 -days 1024 -out myLocalCA.pem

At this point, you have myLocalCA.pem. This is the public certificate for your new “bouncer”. Now, you need to introduce it to your operating system’s security manager.

Step 2: Make Your OS Trust Your CA

This is the most crucial and most often-missed step. You must import myLocalCA.pem into your system’s trust store. The method varies by OS:

  • macOS: Open “Keychain Access”, go to File -> Import Items, select myLocalCA.pem, and import it into the “System” keychain. Then, find the certificate, double-click it, expand “Trust”, and set “When using this certificate” to “Always Trust”.
  • Windows: Run `certlm.msc`, navigate to “Trusted Root Certification Authorities” -> “Certificates”, right-click, and select “All Tasks” -> “Import”. Follow the wizard to import myLocalCA.pem.
  • Linux (Ubuntu/Debian): Copy the .pem file to /usr/local/share/ca-certificates/myLocalCA.crt (note the extension change!) and then run sudo update-ca-certificates.

Step 3: Issue a Certificate for Your Local Service

Now that your system trusts your CA, you can issue certificates for your services. The key here is using a Subject Alternative Name (SAN) configuration, because modern browsers reject certificates that don’t have one.

First, create a server key and a certificate signing request (CSR).

# Generate a private key for our dev server
openssl genrsa -out dev-server.key 2048

# Create a CSR for our dev server
openssl req -new -key dev-server.key -out dev-server.csr

Next, create a small config file named v3.ext to define the SANs.

# Contents of v3.ext file
authorityKeyIdentifier=keyid,issuer
basicConstraints=CA:FALSE
keyUsage = digitalSignature, nonRepudiation, keyEncipherment, dataEncipherment
subjectAltName = @alt_names

[alt_names]
DNS.1 = localhost
DNS.2 = my-app.local
IP.1 = 127.0.0.1

Finally, sign the CSR with your CA key, using the extension file.

# Issue the final certificate!
openssl x509 -req -in dev-server.csr -CA myLocalCA.pem -CAkey myLocalCA.key -CAcreateserial \
-out dev-server.crt -days 365 -sha256 -extfile v3.ext

Now, you can configure your local web server (Nginx, Caddy, Node.js) to use dev-server.crt and dev-server.key. When you visit https://localhost in your browser, you’ll see a beautiful, green padlock.

Solution 3: The “Modern DevOps” Automated Approach with `mkcert`

While understanding Solution 2 is invaluable, doing it repeatedly is a pain. In my day-to-day work, I use a tool that does all of that for me: mkcert.

It’s a simple command-line tool that automates the entire process of Solution 2. It’s the “I understand the ‘why’, now give me the fastest ‘how’” option.

Step 1: Install it. On macOS with Homebrew, it’s just brew install mkcert. Check their docs for other systems.

Step 2: Create and install your local CA.

# This does steps 1 and 2 from the manual method automatically!
mkcert -install

Step 3: Generate a certificate for your project.

# This generates a valid cert and key file for the given domains
mkcert localhost 127.0.0.1 ::1 my-api.dev.local

That’s it. You now have localhost+2.pem (the certificate) and localhost+2-key.pem (the private key) in your current directory. Point your server to them, and you’re done. No manual OpenSSL commands, no hunting down trust stores. It just works.

A Final Word from the Trenches

Look, we all start by just clicking “Proceed to unsafe”. But taking 30 minutes to understand why your browser is yelling at you and learning how to set up a proper local CA will pay dividends for the rest of your career. It saves you from frustrating debugging sessions and makes your local development environment a true reflection of production. My advice? Go through the manual OpenSSL process once to appreciate what’s happening. Then, install `mkcert` and make your life easy.

Darian Vance - Lead Cloud Architect

Darian Vance

Lead Cloud Architect & DevOps Strategist

With over 12 years in system architecture and automation, Darian specializes in simplifying complex cloud infrastructures. An advocate for open-source solutions, he founded TechResolve to provide engineers with actionable, battle-tested troubleshooting guides and robust software alternatives.


🤖 Frequently Asked Questions

âť“ Why do I get `NET::ERR_CERT_AUTHORITY_INVALID` when using HTTPS locally?

This error arises because your browser’s operating system does not recognize or trust the Certificate Authority (CA) that signed your local SSL certificate. Browsers only trust certificates signed by CAs present in their built-in trust store.

âť“ How does `mkcert` compare to manual OpenSSL for local HTTPS setup?

`mkcert` automates the entire process of creating a local Root CA, installing it into the system’s trust store, and generating certificates with Subject Alternative Names (SANs). Manual OpenSSL provides granular control and deeper understanding but requires executing each step individually, making it more complex and time-consuming.

âť“ What is a common implementation pitfall when setting up local HTTPS with OpenSSL?

A common pitfall is forgetting to import your `myLocalCA.pem` file into your operating system’s trust store or failing to include Subject Alternative Names (SANs) in your service’s certificate. Without these, browsers will continue to reject the certificate, even if it was signed by your custom local CA.

Leave a Reply

Discover more from TechResolve - SaaS Troubleshooting & Software Alternatives

Subscribe now to keep reading and get access to the full archive.

Continue reading