{"record":{"id":"ccd7327ada979783","repo":"caddyserver/caddy","slug":"encrypted-private-keys-are-not-supported-please-d","errorCode":null,"errorMessage":"encrypted private keys are not supported; please decrypt the key first","messagePattern":"encrypted private keys are not supported; please decrypt the key first","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"modules/caddytls/fileloader.go","lineNumber":101,"sourceCode":"\t\tcertData, err := os.ReadFile(pair.Certificate)\n\t\tif err != nil {\n\t\t\treturn nil, err\n\t\t}\n\t\tkeyData, err := os.ReadFile(pair.Key)\n\t\tif err != nil {\n\t\t\treturn nil, err\n\t\t}\n\n\t\tvar cert tls.Certificate\n\t\tswitch pair.Format {\n\t\tcase \"\":\n\t\t\tfallthrough\n\n\t\tcase \"pem\":\n\t\t\t// if the start of the key file looks like an encrypted private key,\n\t\t\t// reject it with a helpful error message\n\t\t\tif strings.Contains(string(keyData[:40]), \"ENCRYPTED\") {\n\t\t\t\treturn nil, fmt.Errorf(\"encrypted private keys are not supported; please decrypt the key first\")\n\t\t\t}\n\n\t\t\tcert, err = tls.X509KeyPair(certData, keyData)\n\n\t\tdefault:\n\t\t\treturn nil, fmt.Errorf(\"unrecognized certificate/key encoding format: %s\", pair.Format)\n\t\t}\n\t\tif err != nil {\n\t\t\treturn nil, err\n\t\t}\n\n\t\tcerts = append(certs, Certificate{Certificate: cert, Tags: pair.Tags})\n\t}\n\treturn certs, nil\n}\n\n// Interface guard\nvar (","sourceCodeStart":83,"sourceCodeEnd":119,"githubUrl":"https://github.com/caddyserver/caddy/blob/50e54ee279aa1e504fe218ca49ab6ae16c100410/modules/caddytls/fileloader.go#L83-L119","documentation":"The TLS file certificate loader (tls.certificates.load_files / FileLoader) reads the PEM key file and inspects its first 40 bytes; if they contain the string ENCRYPTED — the marker header of PKCS#8/PKCS#1 encrypted key PEMs such as '-----BEGIN ENCRYPTED PRIVATE KEY-----' — it refuses to load, because Go's tls.X509KeyPair cannot consume passphrase-protected keys and Caddy has no prompt/decrypt step. The error tells you to decrypt out-of-band.","triggerScenarios":"tls directive with load / pointing at a certificate/key pair whose key file begins with '-----BEGIN ENCRYPTED PRIVATE KEY-----' (openssl enc-protected RSA/EC keys).","commonSituations":"Keys generated with 'openssl genrsa -aes256' or exported from vaults/browsers with a passphrase; CI copying secured keys into place without decrypting; operators assuming Caddy will prompt for the passphrase (it won't, even interactively).","solutions":["Decrypt the key to an unencrypted PEM: openssl rsa -in encrypted.key -out decrypted.key (RSA) or openssl pkey -in encrypted.key -out decrypted.key, then point the config at decrypted.key.","Restrict the decrypted file's permissions to the Caddy user (chmod 600) since it is now plaintext.","Prefer letting Caddy automate certificates (ACME) instead of supplying encrypted files.","For automated pipelines, decrypt in a pre-deploy step fed from a secrets manager, never committing the plaintext key."],"exampleFix":"# before\n$ openssl genrsa -aes256 -out site.key 2048   # encrypted\ntls /path/cert.pem /path/site.key  -> error\n\n# after\n$ openssl pkey -in site.key -out site.plain.key   # enter passphrase once\ntls /path/cert.pem /path/site.plain.key","handlingStrategy":"validation","validationCode":"// Detect encrypted PEM keys before handing them to the loader.\nfunc isEncryptedKey(keyPath string) (bool, error) {\n    data, err := os.ReadFile(keyPath)\n    if err != nil {\n        return false, err\n    }\n    head := data\n    if len(head) > 40 {\n        head = head[:40]\n    }\n    return strings.Contains(string(head), \"ENCRYPTED\"), nil\n}","typeGuard":null,"tryCatchPattern":"if err != nil && strings.Contains(err.Error(), \"encrypted private keys are not supported\") {\n    // decrypt out-of-band: openssl pkey -in enc.key -out plain.key; update config path\n}","preventionTips":["Generate keys unencrypted for server use: openssl genrsa -out site.key 2048 (no -aes* flag).","Decrypt in a pre-deploy step from your secrets manager; never expect Caddy to prompt.","chmod 600 decrypted keys and restrict them to the service user.","Prefer ACME-automated certificates to avoid handling key files at all."],"tags":["tls","certificates","pem","encryption","config"],"backgroundTag":null,"analyzedSha":"50e54ee279aa1e504fe218ca49ab6ae16c100410","analyzedAt":"2026-08-15T09:20:21.641Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}