Repository navigation
Certificate Management
Manage automatic ACME certificates and imported custom certificates in Caddy Proxy Manager.
- How Certificates Work
- Certificates Page Overview
- ACME Certificates
- Import Custom Certificates
- CA Certificates
- Renewal and Monitoring
- Security Considerations
- Troubleshooting
Caddy Proxy Manager supports three certificate paths:
- Automatic ACME (recommended)
- Caddy obtains and renews certificates automatically (Let's Encrypt / ZeroSSL)
- Used when a proxy host is set to
Managed by Caddy (Auto)
- Imported custom certificates
- You provide certificate PEM + private key PEM
- Use for internal CAs, pre-issued wildcard certs, or compliance-driven workflows
- Built-in CA certificates
- Generate your own CA root and issue internal client certificates
- Useful for mTLS or testing without a third-party CA
The Certificates page has four tabs:
- ACME
- Proxy hosts currently using automatic certificate management
- Shows domains and host enabled/disabled status
- Server-side paginated
- Imported
- Custom certificates stored in the application database
- Shows issuer, expiry, covered domains, and which hosts use each cert
- CA / mTLS
- Internal CA roots you have created
- Issue and manage client certificates signed by each CA
- Download CA cert, issue new client certs, view existing issued certs
- Roles
- mTLS roles: named groups of issued client certificates
- Used by path-based access rules on mTLS proxy hosts (see Feature Guide mTLS RBAC)
For each auto-managed proxy host, the table displays:
- Proxy host name
- Domains
- Host enabled/disabled status
Caddy manages ACME certificate issuance and renewal entirely on its own. The ACME tab lists which proxy hosts use automatic certificates so you can verify coverage.
ACME table pagination is server-side.
- Default page size:
25 - URL param:
?page=N
Use custom import when ACME is not suitable.
- Open Certificates.
- Scroll to Import Custom Certificate.
- Provide:
- Certificate Name
- Domains (one per line)
- Certificate PEM (full chain recommended)
- Private Key PEM
- Click Import Certificate.
For each imported certificate, you can:
- Review issuer and expiry
- See covered domains
- See which proxy hosts currently reference it
- Update fields
- Delete the certificate
When editing, keep certificate/key pairs matched.
The built-in CA lets you create internal certificate authorities and issue client certificates.
- Open Certificates → CA / mTLS.
- Click Add CA Certificate.
- On the Generate tab, provide a name, a Common Name (CN) and a validity period.
- Click Generate CA Certificate.
The Import PEM tab adds an existing CA certificate without a private key. CPM can then validate client certificates signed by that CA, but cannot issue new ones.
The CA root certificate can be downloaded and installed in browsers or systems that need to trust certificates issued by this CA.
- Open the menu on a CA row and select Issue Client Cert, or expand the row and click Issue Cert.
- Provide a Common Name (CN), a Validity in days and an Export Password. Compatibility mode (on by default) uses 3DES for broader OS/browser import compatibility; turn it off for AES-256.
- Click Issue Certificate.
- Download the
.p12bundle (client certificate, private key and CA chain). The client private key is not stored server-side.
These options appear only for a CA with a stored private key. With Feature Guide Instance Sync, issue client certificates on the master (see CA private keys).
Expand a CA row to see its active client certificates, and click Manage to list all certificates issued by that CA, including expiry status, and to revoke them.
(since v1.13.1)
CA private keys are encrypted at rest (AES-256-GCM, keyed from SESSION_SECRET), like imported certificate keys. Keys stored in plaintext by older releases are encrypted on the next start, which logs Encrypted N legacy CA private key(s).
With Instance Sync, CA private keys never leave the master: slaves receive the CA certificates without their private keys, and the first sync removes the copies that older versions stored on slaves. As a result:
- Slaves keep validating client certificates, but cannot issue new ones.
- A slave promoted to master cannot issue certificates from the existing CAs.
- To keep the ability to issue, back up the master's database together with its
SESSION_SECRET. Neither is usable without the other.
If SESSION_SECRET changes without the old value in SESSION_SECRET_PREVIOUS, issuing fails with a clear error (see Troubleshooting). Client certificates already issued keep working, because validating them only needs the CA certificate.
- mTLS (mutual TLS) between services inside a trusted network
- Internal testing without purchasing a certificate
- Short-lived client credentials that need to be revoked quickly
- Renewed automatically by Caddy
- Renewal attempts start before expiration
- No manual renew action is usually required
- Not auto-renewed
- You must replace them before expiry
Caddy logs:
docker compose logs caddy | grep -i acmePublic endpoint check:
echo | openssl s_client -connect your-domain.com:443 2>/dev/null | openssl x509 -noout -issuer -datesImported certificate private keys and CA private keys are stored in SQLite, encrypted at rest with AES-256-GCM, using a key derived from SESSION_SECRET (CA private keys since v1.13.1). Anyone who has both the database and SESSION_SECRET can decrypt them.
After rotating SESSION_SECRET, keep the old value in SESSION_SECRET_PREVIOUS at least until the next successful start, so the stored keys are re-encrypted with the new secret (see Security Configuration#secret-rotation).
Recommendations:
- Restrict data volume/file permissions
- Encrypt backups
- Rotate imported certificates regularly
- Limit host access to backup artifacts
- ACME cert material lives in Caddy's data volume
- Imported cert material lives in the app database
- CA private keys live in the app database (with Instance Sync, only on the master; slaves hold the CA certificates only)
Checks:
- Domain resolves to your public IP
- Ports
80/443reachable (for HTTP-01/TLS-ALPN-01) - DNS provider configured in Settings → DNS Providers for wildcard or internal-only domains (see DNS Provider Configuration)
- ACME email configured in Settings
Verify key/cert match:
openssl x509 -noout -modulus -in cert.pem | openssl md5
openssl rsa -noout -modulus -in key.pem | openssl md5Hashes must match.
-
"The CA private key cannot be decrypted with the current SESSION_SECRET. Restore the previous secret via SESSION_SECRET_PREVIOUS or create a new CA." The CA key was encrypted under an earlier
SESSION_SECRET. Set that value inSESSION_SECRET_PREVIOUSand recreate the web container (docker compose up -d), or create a new CA. Certificates already issued by the CA keep working. The web container logsFailed to decrypt the private key of CA certificate <id>; SESSION_SECRET may have changed. - No Issue Client Cert option: the CA has no stored private key. This is the case for CAs added through Import PEM, and for every CA on an Instance Sync slave. Issue client certificates on the master.
- DNS Provider Configuration
- Feature Guide Proxy Hosts
- Environment Variables Reference
- Security Configuration
- Troubleshooting
Need help? Open an issue with logs and non-sensitive certificate metadata (never share private keys).