docs / guides

Trusting lokal from Node, Python and curl

Point tools that ship their own certificate bundle at lokal's CA with one line in your shell.

On this page

Browsers and most macOS tools check certificates against the macOS keychain, so they trust lokal as soon as setup is done. Node, Python and some other tools ship their own certificate bundles instead, and reject lokal’s certificates until you point them at lokal’s CA. lokal env does that.

Set it up in your shell#

terminal
$ eval "$(lokal env)"                 # zsh, bash
$ lokal env --shell fish | source     # fish

Run it in the shell that starts your dev servers and scripts, before you start them. Node, for example, reads NODE_EXTRA_CA_CERTS only at startup, so a process that was already running keeps failing until you restart it.

lokal env only prints shell exports, so you can see exactly what it sets:

terminal
$ lokal env
export NODE_EXTRA_CA_CERTS='/Users/you/Library/Application Support/lokal/ca/root.pem'
export SSL_CERT_FILE='/Users/you/Library/Application Support/lokal/ca/bundle.pem'
export REQUESTS_CA_BUNDLE='/Users/you/Library/Application Support/lokal/ca/bundle.pem'
export CURL_CA_BUNDLE='/Users/you/Library/Application Support/lokal/ca/bundle.pem'

With --shell fish, the same variables come out as set -gx lines.

What each variable does#

VariableRead byPoints at
NODE_EXTRA_CA_CERTSNodelokal’s CA certificate (root.pem). Node adds it to its built-in roots
SSL_CERT_FILEOpenSSL, which Python’s ssl module and urllib useThe bundle (bundle.pem)
REQUESTS_CA_BUNDLEPython’s requests libraryThe bundle
CURL_CA_BUNDLEcurl builds that use their own CA bundleThe bundle

The last three variables replace a tool’s whole list of trusted roots instead of adding to it. That’s why they point at a bundle that holds the macOS system roots plus lokal’s CA: lokal URLs work, and public HTTPS sites keep working too.

Setup writes the bundle. lokal env writes it again whenever it’s more than 30 days old, so it picks up changes to the macOS system roots.

Make it permanent#

Add the line to your shell profile, so every new shell gets it. For zsh, that’s ~/.zshrc. For bash, it’s ~/.bash_profile or ~/.bashrc:

shell
eval "$(lokal env)"

For fish, add this to ~/.config/fish/config.fish:

fish
lokal env --shell fish | source

lokal env needs lokal to be set up. Before setup, it prints lokal isn't set up yet and sets nothing, so run lokal setup first. The same goes after lokal uninstall: the CA files stay on disk, but lokal env stops exporting them, so a leftover line in your profile can’t keep trusting lokal’s CA. Uninstall reminds you to remove the line.

Use the CA file directly: lokal ca path#

lokal ca path prints the path of lokal’s CA certificate. Use it to set a variable for a single command:

terminal
$ lokal ca path
/Users/you/Library/Application Support/lokal/ca/root.pem
$ NODE_EXTRA_CA_CERTS="$(lokal ca path)" node app.js

The path contains a space, so keep the quotes when you use it in a shell.

Recent Node versions can also use the macOS keychain directly, with node --use-system-ca. Then Node needs no environment variable at all.

Which tools need it#

ToolTrusts lokal after setup?
Safari, Chrome and other browsers that use the keychainYes
FirefoxYes. Firefox has its own trust store, so setup turns on its security.enterprise_roots.enabled preference in each profile
macOS tools, including /usr/bin/curlYes
NodeWith lokal env, or node --use-system-ca
Python (requests, urllib)With lokal env
Other curl buildsWith lokal env (CURL_CA_BUNDLE), if they use their own bundle

The Firefox preference makes Firefox trust every root CA in the macOS keychain, not only lokal’s. The security model explains the trade-off and how to undo it. If you create a Firefox profile after setup, run lokal setup again to cover it.

When it still fails#

Errors like unable to get local issuer certificate, self-signed certificate in certificate chain or CERTIFICATE_VERIFY_FAILED mean the tool doesn’t trust lokal’s CA yet.

  • Make sure you ran eval "$(lokal env)" in the same shell, before the process started.
  • Run lokal doctor. If ca.trusted fails, the CA isn’t trusted by macOS either: run lokal setup, which re-trusts it and asks for your password.
  • A handshake error rather than a certificate warning (curl says tlsv1 alert access denied) usually means the name isn’t configured. Check lokal list.

Troubleshooting has more.