Serve your tool over HTTPS locally¶
Recipes beyond the tutorial happy path. Each is independent; take the one you need.
Serve on a LAN address so a phone can reach it¶
Add the bind host or IP to the certificate's subject alternative names. EnsureServed
re-mints automatically when the host list changes, so adding one is enough:
pair, err := localca.EnsureServed(ctx, cfg,
[]string{"localhost", "127.0.0.1", "::1", "192.168.1.20"})
Anything in the list that parses as an IP address becomes an IP SAN; everything else becomes a DNS name. Nothing validates that a DNS name is plausible or resolvable.
Ask for every name you need in one call. localca caches a single leaf per data
directory, so two calls with different host lists overwrite each other rather than
accumulating — see
only one leaf is cached.
The root only has to be installed once, on the serving machine. Other devices trust the
certificate only if you import the root into their trust store — copy DataDir/rootCA.pem
across. Copy the certificate, never rootCA-key.pem.
Install into one trust store rather than both¶
EnsureServed targets every supported store. To choose, drive the Authority directly:
a, err := localca.New(cfg)
if err != nil {
return err
}
_, err = a.Install(ctx, localca.StoreNSS) // Firefox and Chromium-on-Linux; no password prompt
_, err = a.Install(ctx, localca.StoreSystem) // system-wide; prompts for elevation
StoreSystem— the OS store, read by Chrome, Safari, Edge and Go's HTTP client. Needs administrator privileges.StoreNSS— the NSS databases used by Firefox, and by Chromium on Linux. User-level, no password, but needscertutil.
Which mechanism each uses per platform is in platform support.
There is no matching scope on removal: Uninstall always targets both stores, and therefore
always asks for elevation. To remove an NSS-only install without a password prompt, use
certutil -D against the profile directly.
Get Firefox to trust the certificate¶
Firefox reads NSS, not the OS trust store, and the NSS install needs certutil:
sudo apt-get install -y libnss3-tools # Debian, Ubuntu
sudo dnf install -y nss-tools # Fedora, RHEL
brew install nss # macOS
Then install again — Install is idempotent, so re-running it costs nothing:
Restart Firefox afterwards; it caches trust decisions for the life of the process.
Without certutil, localca skips NSS and carries on rather than failing. Chrome, Safari,
Edge and Go still trust the certificate; Firefox alone does not. On a box where you cannot
install packages, unpack the binary without root.
Find out where the root is currently trusted¶
state, err := a.Installed(ctx)
if err != nil {
return err // "no root CA provisioned" means nothing has been minted yet
}
fmt.Println(state.System, state.NSS)
System is read from DataDir/trust-install.json, which records localca's own installs —
the OS store has no portable "is this trusted?" query. NSS is queried live with certutil,
and is true only when the root is present in every NSS profile found.
Installed never mints a root; it errors if there isn't one.
Get a certificate without touching the trust store¶
Authority.Leaf mints an in-memory certificate and does nothing else — no install, no
files, no cache:
Every call mints a fresh certificate and key. It errors if no root has been provisioned yet,
so it is not a substitute for EnsureServed on first run.
Change how long certificates last¶
cfg := localca.Config{
DataDir: dir,
AppName: "myapp",
RootTTL: 5 * 365 * 24 * time.Hour, // default is ten years
LeafTTL: 30 * 24 * time.Hour, // default is 90 days
}
RootTTL applies only when a root is minted; changing it later does not extend an existing
one. Keep LeafTTL above seven days, or the renewal window defeats the cache and every call
re-mints. Both are covered in the
configuration reference.
A leaf is never issued past its root's expiry. Once the root has less than one leaf lifetime
left, every minted leaf is clamped to the root's NotAfter and localca logs a WARN
telling you to re-install. You will only see it if you attach a logger:
Remove everything¶
_ = a.Uninstall(ctx) // out of the trust stores, key kept
_ = a.Uninstall(ctx, localca.Purge()) // ...and delete the stored root cert + key
Purge() does not delete the cached leaf. Delete it too, or the next EnsureServed here
serves a certificate signed by the root you just removed:
Run Uninstall before deleting the data directory. Without the stored root certificate,
localca has no way to identify what to remove, and the entry stays in your system trust
store until you delete it by hand.
Provision in CI or a container¶
Trust installation needs either root or an interactive terminal, and CI usually has neither. Options:
- Run the container as root. The elevation pre-flight passes on
euid == 0and nothing prompts. - Install into NSS only, which needs no privileges at all — enough if the tests drive a browser rather than the OS store.
-
Skip trust entirely and have the test client trust
rootCA.pemexplicitly, which needs no install:
Handle ErrElevationUnavailable so a CI run fails with a clear message rather than an
unexplained error:
if _, err := a.Install(ctx); errors.Is(err, localca.ErrElevationUnavailable) {
// no privileges available here — fall back or skip
}
Keep a test off the host machine entirely¶
Injecting an in-memory filesystem is not enough on its own: the default trust-store backend
shells out to real commands regardless of what WithFS is set to. Replace both:
a, err := localca.New(cfg,
localca.WithFS(afero.NewMemMapFs()), // root and leaf in memory
localca.WithTrustStore(fakeTrustStore{}), // nothing touches the real store
localca.WithClock(func() time.Time { return fixedTime }),
)
A TrustStore whose State reports System: true makes EnsureServed skip the install
path completely.