caddyserver/caddy · error
access control %d public key %d: parsing base64 certificate
Error message
access control %d public key %d: parsing base64 certificate DER: %v
What it means
When enabling the remote admin endpoint, Caddy decodes each base64-DER client certificate listed under admin.remote.access_control[].public_keys to build the client CA pool. If any entry is not valid base64 or not a parseable DER certificate, this error reports which access control (i) and key (j) failed, wrapping the x509/base64 cause.
Source
Thrown at admin.go:552
if err != nil {
return err
}
// make the HTTP handler but disable Host/Origin enforcement
// because we are using TLS authentication instead
handler, err := cfg.Admin.newAdminHandler(addr, true, ctx)
if err != nil {
return err
}
// create client certificate pool for TLS mutual auth, and extract public keys
// so that we can enforce access controls at the application layer
clientCertPool := x509.NewCertPool()
for i, accessControl := range cfg.Admin.Remote.AccessControl {
for j, certBase64 := range accessControl.PublicKeys {
cert, err := decodeBase64DERCert(certBase64)
if err != nil {
return fmt.Errorf("access control %d public key %d: parsing base64 certificate DER: %v", i, j, err)
}
accessControl.publicKeys = append(accessControl.publicKeys, cert.PublicKey)
clientCertPool.AddCert(cert)
}
}
// create TLS config that will enforce mutual authentication
if identityCertCache == nil {
return fmt.Errorf("cannot enable remote admin without a certificate cache; configure identity management to initialize a certificate cache")
}
cmCfg := cfg.Admin.Identity.certmagicConfig(remoteLogger, false)
tlsConfig := cmCfg.TLSConfig()
tlsConfig.NextProtos = nil // this server does not solve ACME challenges
tlsConfig.ClientAuth = tls.RequireAndVerifyClientCert
tlsConfig.ClientCAs = clientCertPool
// convert logger to stdlib so it can be used by HTTP server
serverLogger, err := zap.NewStdLogAt(remoteLogger, zap.DebugLevel)View on GitHub (pinned to 50e54ee279)
Solutions
- Produce the correct value: openssl x509 -in client.pem -outform DER | base64 -w0
- Check the indicated indices (access control %d, public key %d) in your config against the error to find the exact bad entry
- Remove whitespace/newlines from the base64 string
- Verify the DER parses: openssl x509 -inform DER -in client.der -noout
Example fix
# before: base64 of PEM text (wrong) public_keys: ["LS0tLS1CRUdJTiBDRVJUSUZ..."] # after: base64 of DER bytes openssl x509 -in client.pem -outform DER | base64 -w0 public_keys: ["MIIBvzCCAYWgAwIBAgIU..."]
Defensive patterns
Strategy: validation
Validate before calling
func toBase64DER(pemCert []byte) (string, error) {
block, _ := pem.Decode(pemCert)
if block == nil {
return "", errors.New("input is not PEM")
}
if _, err := x509.ParseCertificate(block.Bytes); err != nil {
return "", fmt.Errorf("not a certificate: %v", err)
}
return base64.StdEncoding.EncodeToString(block.Bytes), nil
} Prevention
- Generate values only with openssl x509 -outform DER | base64 -w0
- Never base64 the PEM text itself
- Write a config-rendering test that decodes every public_keys entry and parses it as DER
When it happens
Trigger: admin.remote config where a public_keys entry is base64 of PEM instead of DER; truncated or whitespace-mangled base64; a certificate encoded with standard base64 including '=' padding the decoder rejects, or simply not a certificate at all.
Common situations: Converting a PEM client cert to base64 without first converting to DER (base64 of the PEM text); copy-paste truncation; exporting the public key bytes instead of the full certificate; line-wrapped base64 pasted with newlines.
Understand the failure class
- SSL/TLS and certificate errors — how TLS handshakes and certificate validation fail.
Related errors
- cannot enable remote admin without a certificate cache; conf
- parsing certificate at index %d: %v
- no metrics registry found
- loading identity issuer modules: %s
- no identifiers configured
AI-assisted analysis of caddyserver/caddy@50e54ee279 (2026-08-15).
Data as JSON: /api/errors/a89b57b1c1b5e23c.
Report an issue: GitHub.