Skip to content

Serve your tool over HTTPS locally

Recipes beyond the getting-started happy path.

Serve on a LAN IP (mobile / other-device access)

Add the bind host/IP to the leaf's SANs so a phone on the same network trusts it — the leaf is re-minted automatically when the host list changes:

pair, err := localca.EnsureServed(ctx, cfg,
    []string{"localhost", "127.0.0.1", "::1", "192.168.1.20"})

The root only has to be installed once on the serving machine. Other devices that should trust the cert need the root imported into their trust store — export it from DataDir/rootCA.pem.

Scope which trust stores you touch

EnsureServed targets all supported stores. For finer control, drive the Authority directly:

a, _ := localca.New(cfg)
_, _ = a.Install(ctx, localca.StoreNSS)    // Firefox/Chromium only (no OS elevation)
_, _ = a.Install(ctx, localca.StoreSystem) // system store only (prompts for elevation)
  • StoreSystem — the OS store (Keychain / ca-certificates / CryptoAPI). Read by Chrome, Safari, Edge, and the Go HTTP client. Requires elevation.
  • StoreNSS — the shared NSS DB used by Firefox and Chromium. User-level, but needs certutil.

Install certutil for Firefox trust

NSS install needs the certutil tool. Without it, the system store still works (Chrome/Safari/Edge trust the cert) but Firefox won't — localca skips NSS and carries on rather than failing.

# Debian/Ubuntu
sudo apt-get install -y libnss3-tools
# Fedora
sudo dnf install -y nss-tools
# macOS
brew install nss

Check where the root is trusted

state, _ := a.Installed(ctx)
fmt.Println(state.System, state.NSS)

The system state is tracked in DataDir/trust-install.json (the OS store has no portable "is-trusted?" query); NSS is queried live via certutil.

Remove everything

_ = a.Uninstall(ctx)                 // remove from trust stores, keep the key
_ = a.Uninstall(ctx, localca.Purge()) // …and delete the stored root key + cert

Custom validity

cfg := localca.Config{
    DataDir: dir,
    AppName: "myapp",
    RootTTL: 5 * 365 * 24 * time.Hour, // default ~10y
    LeafTTL: 30 * 24 * time.Hour,      // default 90d
}