LiveAPI Demo

Serving Local Apps Securely with Caddy and Authentik: Fixing TLS Warnings in Development

Hi there! I’m Maneshwar. Right now, I’m building LiveAPI, a first-of-its-kind tool that helps you automatically index API endpoints across all your repositories. LiveAPI makes it easier to discover, understand, and interact with APIs in large infrastructures.

When you’re building a full-stack platform with multiple services — like a frontend UI, a backend API (e.g., backend Server), and an auth system (e.g., Authentik) — you often want to wire them together with secure, production-like communication… even in local development.

That’s where Caddy shines. It’s a modern web server that handles automatic HTTPS, reverse proxies, compression, and more — all with a friendly config format.

But when you use:

tls internal

Caddy issues self-signed TLS certificates for *.localhost domains, which are not trusted by browsers out of the box. This results in:

❗️”Your connection is not private”
❗️”NET::ERR_CERT_AUTHORITY_INVALID”

Even though everything works.

So let’s fix that, and look at use cases for this setup.

Caddy Setup: Serving Authentik, backend, and dev

Here’s what we’re running in Docker:

Service URL Port
dev UI https://dev.localhost 3030
backend Server https://backend.localhost 1337
Authentik https://auth.localhost 9000

And the Caddy config looks like this:

dev.localhost {
    tls internal
    encode zstd gzip
    reverse_proxy onprem-dev-ui-1:3030
    log {
        output stdout
        format console
    }
}

backend.localhost {
    tls internal
    encode zstd gzip
    reverse_proxy onprem-backend-server-1:1337
    log {
        output stdout
        format console
    }
}

auth.localhost {
    tls internal
    encode zstd gzip
    reverse_proxy onprem-server-1:9000
    log {
        output stdout
        format console
    }
}

http://dev.localhost, http://backend.localhost, http://auth.localhost {
    redir https://{host}{uri} permanent
}

🔁 The reverse proxy uses Docker container names like onprem-backend-server-1, which are resolvable inside Docker’s internal network.

The Problem: TLS Certificate Warning

When you visit https://auth.localhost, the app loads, but your browser screams:

  • “Not secure”
  • “NET::ERR_CERT_AUTHORITY_INVALID”

This happens because Caddy’s internal CA is not trusted by your OS or browser.

The Fix: Trust Caddy’s Internal CA

If you’re on Linux, run:

sudo cp ~/.local/share/caddy/pki/authorities/local/root.crt /usr/local/share/ca-certificates/caddy-root.crt
sudo update-ca-certificates

Then restart your browser.

This installs the root certificate used by Caddy into your system trust store. Now your browser trusts the *.localhost HTTPS certs Caddy issues.

Why Use This Setup?

Running your stack locally with TLS and auth has huge benefits:

1. Test OAuth / OIDC flows locally

Authentik (or any IdP) will reject http:// callbacks. With Caddy and TLS, you can test these flows safely on https://localhost.

2. Mirror production setup

If your production setup uses reverse proxies, TLS, and secure cookies, mimicking that in local dev avoids surprises later.

3. Cleaner URLs

Instead of localhost:3000, localhost:9000, etc., you get:

https://dev.localhost
https://auth.localhost
https://backend.localhost

4. Secure internal communication

If you’re testing things like JWT, session cookies, or API security policies, HTTPS is often required.

Bonus: Add .localhost domains

Make sure you add entries to your /etc/hosts file:

127.0.0.1 dev.localhost
127.0.0.1 auth.localhost
127.0.0.1 backend.localhost

Conclusion

With a little bit of Caddy config and one-time CA installation, you can run a production-grade HTTPS setup on localhost, complete with secure OAuth logins via Authentik and multiple reverse proxied apps.

This gives you confidence in local development and makes debugging identity flows and secure APIs far easier.

LiveAPI helps you get all your backend APIs documented in a few minutes.

With LiveAPI, you can generate interactive API docs that allow users to search and execute endpoints directly from the browser.

LiveAPI Demo

If you’re tired of updating Swagger manually or syncing Postman collections, give it a shot.

Similar Posts