LPM CLI

lpm cert

Create, inspect, and rotate certificates for trusted local HTTPS.

lpm cert manages the local certificate authority (CA) and project certificates for local HTTPS.

lpm cert <ACTION> [--host <HOST>] [--project <PROJECT>] [--keep-old-trusted <DAYS>] [--fail-on-missing] [--dry-run] [--json]

Use this command for machine setup, certificate files for another tool, or certificate recovery. For daily development, use lpm dev.

ActionPurpose
statusShow CA trust, expiry, project certificate validity, and permission problems.
trustCreate the root CA if necessary and install its certificate in the trust store.
generateCreate or renew the certificate for the project.
uninstallRemove the active root CA from the trust store. Keep its files.
rotateReplace the root CA and reissue known project certificates.
reconcileRecover interrupted rotation and remove expired grace entries or stale files.

Quickstart

Run these commands from your project directory or one of its subdirectories:

lpm cert trust
lpm cert generate
lpm cert status

generate writes .lpm/certs/cert.pem and the private key .lpm/certs/key.pem in the project. The project's .lpm/ directory keeps itself out of Git through .lpm/.gitignore, so neither file is committed. See Files LPM CLI creates. Git still commits files that it already tracks, so while it tracks a file in .lpm/certs/, under any spelling the file system treats as the same file, in the project's repository or in a repository at .lpm/ or .lpm/certs/, generate and rotate refuse to write the key and name the git rm --cached command that untracks it. Commit after running it. They also refuse while Git can't tell whether it tracks one there, as when Git can't be run in a project inside a repository.

generate and status act on the nearest directory at or above the current one that has a package.json or an lpm.json, stopping before your home directory. They print that directory when it is not the current one. generate refuses a directory whose .lpm would be the LPM home. trust, uninstall, rotate, and reconcile act on machine-wide state.

Examples

lpm cert generate --host app.localhost --host api.app.localhost
lpm cert status --json
lpm cert rotate --project ../web --project ../api --fail-on-missing
lpm cert rotate --keep-old-trusted 14
lpm cert reconcile --dry-run --json
lpm cert reconcile
lpm cert uninstall

Use HTTPS from lpm.json

For automatic certificate setup, enable HTTPS next to package.json:

lpm.json
{
  "$schema": "https://cli.lpm.dev/schemas/lpm.json",
  "https": true
}
lpm dev

LPM CLI prepares the certificate and serves HTTPS in front of your application. The application can continue to serve plain HTTP.

If the CA is not trusted, an interactive run asks for consent. In a non-interactive run, approve trust installation explicitly:

lpm dev --yes

For a one-run override:

lpm dev --no-https
lpm dev --https --yes

--yes approves LPM CLI consent. Operating-system authentication can still be necessary. For unattended development runs, install trust during machine setup with lpm cert trust.

Use a project hostname

lpm.json
{
  "proxy": {
    "host": "app.localhost",
    "port": 9443,
    "httpRedirect": false
  }
}
lpm dev

The hostname enables certificate setup and route registration. For multiple services, use distinct services.<name>.host values.

LPM CLI skips hosts-file edits for names below .localhost. Name resolution depends on your browser and operating system.

See lpm proxy for listener configuration and lpm hosts for other local names.

Generate certificate files

lpm cert generate
lpm cert generate --host app.localhost --host api.app.localhost

The default names are localhost, 127.0.0.1, and ::1. Repeat --host for additional Subject Alternative Names (SANs).

generate reads the cert configuration in lpm.json. It does not import names from proxy.host or services.<name>.host. Pass those names with --host for manual generation.

A valid certificate is reused if it covers the requested names. Generation repairs unusable material and renews certificates with 30 days or less remaining.

generate can create files before the root CA is trusted. It does not install trust. Browsers require lpm cert trust before they accept the certificates.

Permit more DNS names

The cert configuration controls additional DNS subtrees that a project certificate can cover:

lpm.json
{
  "cert": {
    "extraPermittedDns": ["myapp.internal"],
    "allowPublicDns": false
  }
}
lpm cert generate --host api.myapp.internal

extraPermittedDns permits names. It does not add SANs or proxy routes.

Each entry must be a bare, multi-label hostname. Schemes, ports, paths, wildcards, and leading dots are invalid.

The accepted local suffixes are .local, .test, .localhost, .internal, and .home.arpa. Public DNS names require explicit permission:

lpm.json
{
  "cert": {
    "extraPermittedDns": ["staging.example.com"],
    "allowPublicDns": true
  }
}

Enable allowPublicDns only for names that you control. This configuration permits your local certificates to cover those public names.

Inspect and repair certificates

lpm cert status
lpm cert status --json

status inspects the nearest project. It does not renew certificates or recover interrupted writes.

The output includes root trust, expiry, SANs, renewal status, and permission problems. It checks that the project key matches its certificate and that the certificate chains to the active root.

JSON includes project.valid and project.error. An absent project certificate has valid: false and error: null. An unusable certificate has a reason in error.

success: true means the inspection completed. It does not mean HTTPS is ready.

If the project key or certificate is unusable, regenerate it with the required names:

lpm cert generate --host app.localhost

If the root is not trusted:

lpm cert trust

Repair unsafe permissions

On Unix systems, certificate directories use mode 0700. Private key files use mode 0600. On macOS, LPM CLI also removes the access list entries that they take from their directory. On Windows, they have a protected access list that admits only you and SYSTEM.

LPM CLI refuses to sign with a group-readable or world-readable CA private key. status prints a repair command for permission problems.

Run the printed command, then retry the failed operation.

Trust stores and file locations

The root CA files default to ~/.lpm/certs/. LPM_HOME changes the LPM CLI state directory. Project certificates remain under <project>/.lpm/certs/.

PlatformTrust behavior
macOSUses the user login Keychain without sudo.
LinuxUses a supported update-ca-certificates or update-ca-trust installation. Uses sudo unless already root.
WindowsUses elevated certutil for the machine Root store.
Other systemsRequires manual CA installation.

Trust checks and removal identify the certificate by fingerprint, not only its name.

Remove CA trust

lpm cert uninstall

The command keeps the root CA files. LPM CLI identifies the trust entry to remove from the on-disk certificate, so it must exist, unless a pending write described next holds the authority. Where Git could commit the LPM home, a certificate write that stopped part way isn't completed, as completing it would write the CA's private key into a file Git could commit; lpm cert uninstall then also removes the pending CA's trust entry and deletes the pending write, which holds that CA's private key. If the write had already put its certificate in place, that rootCA.pem is left without its own key, which went with the pending write: delete rootCA.pem and rootCA-key.pem from the LPM home's certs/, and lpm cert trust creates and trusts a new CA.

To trust the same CA again:

lpm cert trust

Root name restrictions

A root created with LPM_CERT_NAME_CONSTRAINTS=1 limits the names that project certificates can use. Project cert configuration cannot expand that root policy.

LPM CLI rejects names outside the root restrictions before issuance or TLS publication. Use a permitted local hostname or explicitly rotate the root with the intended policy.

See local HTTPS root restrictions for the supported name ranges.

Rotate the root CA

Root CA warnings start with fewer than 60 days remaining. Rotate before expiry or after a private-key exposure:

lpm cert rotate

Rotation reissues certificates for recorded projects. Repeat --project to include more directories:

lpm cert rotate --project ../web --project ../api --fail-on-missing

By default, rotation skips directories that no longer exist. --fail-on-missing makes a missing directory an error.

Hard rotation refuses to proceed while known local TLS consumers remain active. Stop those development or proxy sessions before rotation.

Keep old trust during a transition

lpm cert rotate --keep-old-trusted 14

The accepted range is 0–90 days. A positive grace period keeps the old root trusted and permits active TLS consumers during rotation.

Restart those consumers so they load the new certificate chain. After the grace period expires, run lpm cert reconcile to remove old trust.

A grace period keeps the old identity trusted. Use hard rotation after a private-key exposure.

Repair interrupted rotation

Preview cleanup:

lpm cert reconcile --dry-run --json

The preview preserves certificate material, trust entries, audit records, and pending recovery state. It can create a synchronization lock.

If an interrupted certificate transaction needs recovery, JSON reports pending_recovery: true. Other cleanup results remain empty until recovery completes.

Stop active local TLS consumers, then apply recovery and cleanup:

lpm cert reconcile

Repeat the preview after recovery to inspect the remaining work. Reconciliation also removes expired grace entries and eligible staging files older than 24 hours.

Flags

FlagActionPurpose
--host <HOST>generateAdd a SAN. Repeat for more names.
--project <PROJECT>rotateInclude another project directory. Repeat for more projects.
--keep-old-trusted <DAYS>rotateDefer old-root removal for 0–90 days.
--fail-on-missingrotateFail if a recorded or explicit project directory is missing.
--dry-runreconcilePreview without certificate or trust mutations.
--jsonAll actionsPrint machine-readable output.

Flags for another action cause an error before certificate changes. See global flags for shared options.

See also