caddyserver/caddy · critical

loading signing key: %v

Error message

loading signing key: %v

What it means

While building the embedded step-ca authority in sign_with_root mode, Caddy loads the root's private key via ca.RootKey(). If storage cannot return the key (missing, unreadable, or the root was imported cert-only without a key), newAuthority fails with this wrapped error. The CA then cannot sign anything until the key is available.

Source

Thrown at modules/caddypki/ca.go:238

// executes at a later time, always has the only copy of the CA so it can access the latest,
// renewed certificates since NewAuthority was called. See #4517 and #4669.
func (ca *CA) NewAuthority(authorityConfig AuthorityConfig) (*authority.Authority, error) {
	// get the root certificate and the issuer cert+key
	rootCert := ca.RootCertificate()

	// set up the signer; cert/key which signs the leaf certs
	var signerOption authority.Option
	if authorityConfig.SignWithRoot {
		// if we're signing with root, we can just pass the
		// cert/key directly, since it's unlikely to expire
		// while Caddy is running (long lifetime)
		var issuerCert *x509.Certificate
		var issuerKey crypto.Signer
		issuerCert = rootCert
		var err error
		issuerKey, err = ca.RootKey()
		if err != nil {
			return nil, fmt.Errorf("loading signing key: %v", err)
		}
		signerOption = authority.WithX509Signer(issuerCert, issuerKey)
	} else {
		// if we're signing with intermediate, we need to make
		// sure it's always fresh, because the intermediate may
		// renew while Caddy is running (medium lifetime)
		signerOption = authority.WithX509SignerFunc(func() ([]*x509.Certificate, crypto.Signer, error) {
			issuerChain := ca.IntermediateCertificateChain()
			issuerCert := issuerChain[0]
			issuerKey := ca.IntermediateKey()
			ca.log.Debug("using intermediate signer",
				zap.String("serial", issuerCert.SerialNumber.String()),
				zap.String("not_before", issuerCert.NotBefore.String()),
				zap.String("not_after", issuerCert.NotAfter.String()))
			return issuerChain, issuerKey, nil
		})
	}

View on GitHub (pinned to 50e54ee279)

Solutions

  1. Provide the root key alongside the root cert: add key_file to the root{} block (cert+key must both be present) or store the key at the expected storage path.
  2. Verify storage integrity: ensure the CA's root key object exists (e.g. ls storage/caddy/pki/<id>/ca/key.pem or your backend's equivalent) and that Caddy's storage user can read it.
  3. If you do not actually need root signing, remove sign_with_root so Caddy signs with a generated intermediate instead.
  4. If the key was lost, regenerate the CA (delete that CA's assets in storage) and re-distribute the new root to trust stores.

Example fix

// before
{"root":{"cert":"file:///etc/caddy/root.crt"},"sign_with_root":true}
// after
{"root":{"cert":"file:///etc/caddy/root.crt","key":"file:///etc/caddy/root.key"},"sign_with_root":true}
Defensive patterns

Strategy: try-catch

Validate before calling

// Before starting Caddy with sign_with_root, confirm both assets exist
// (example for file storage): check <storage>/caddy/pki/<id>/ca/root.crt AND key.pem
if _, err := os.Stat(rootKeyPath); err != nil { log.Fatal("root key missing for sign_with_root") }

Try / catch

// err is returned from CA provisioning; check prefix and surface actionable text
if err != nil {
    if strings.Contains(err.Error(), "loading signing key") {
        // inspect storage for the root key object; re-import root{cert,key} pair
    }
    return fmt.Errorf("pki CA setup failed: %v", err)
}

Prevention

When it happens

Trigger: Enabling sign_with_root on a CA whose root key is absent from storage (root imported as cert only), a storage backend error while reading storageKeyRootKey, or a key PEM that fails to load. The call chain is CA.newAuthority -> ca.RootKey() -> storage.Load(root key).

Common situations: Users importing only root.cert_file without root.key_file; file/Redis/S3 storage permission problems or missing assets after partial provisioning; copied storage where the key file was excluded.

Related errors


AI-assisted analysis of caddyserver/caddy@50e54ee279 (2026-08-15). Data as JSON: /api/errors/a80762b67878dbc2. Report an issue: GitHub.