Skip to content
ssldays

Guide

Where Caddy stores SSL certificates and renewal

Map Caddy automatic HTTPS storage, manual tls paths, and reload steps so renewed material reaches the listener customers hit on port 443.

Updated May 30, 2026 819 words

Understanding the caddy ssl certificate path layout prevents renewals that update files Caddy is not reading, or metadata Caddy never reloads onto the public listener.

Operators search path documentation after renewals succeed on disk yet browsers still warn. Caddy mixes automatic HTTPS assets under a data directory with optional manual tls file directives in the Caddyfile or JSON config.

Paths differ between packages, Docker volumes, and Helm charts, but the mental model is constant: issuance writes to configured storage, site blocks decide what loads, and reload propagates material to TLS listeners. This guide maps those layers and ties them to renewal workflows.

If obtains fail before files update at all, start with Caddy automatic HTTPS renewal failed. If files look correct but strangers see stale serials, continue with Reload caddy after SSL certificate renewal.

What to check

Identify whether each public hostname uses automatic HTTPS, manual tls cert and key paths, or internal CA modes. Automatic mode stores certificates and keys with ACME metadata under the configured data directory, commonly something like /var/lib/caddy on Linux packages.

Manual mode reads PEM paths you specify until removed; those paths are the renewal target for commercial certs or imported bundles. Confirm environment variables such as XDG_DATA_HOME or CADDY_STORAGE when containers override defaults.

List active site blocks and note which names share issuers. Wildcards and on-demand TLS modules may use different storage subtrees or provider credentials even when the root data path is shared.

Compare serial on disk metadata versus openssl on the public hostname. Mismatch means wrong path, wrong site block, or missing reload—not a mystery platform bug.

Step-by-step

Locate configured roots

systemctl show caddy -p Environment --no-pager
caddy adapt --config /etc/caddy/Caddyfile --pretty 2>/dev/null | head

Inspect unit files or container manifests for CADDYPATH, data volume mounts, and user ID running the process.

Enumerate automatic HTTPS assets

sudo find /var/lib/caddy -type f -name '*.crt' -o -name '*.key' 2>/dev/null | head
sudo ls -la /var/lib/caddy/certificates 2>/dev/null

Exact subtree names vary by Caddy version; focus on modification times near your renewal event and pairing cert with key files.

Inspect manual tls paths

grep -E 'tls |cert_file|key_file' /etc/caddy/Caddyfile

When certbot or a vendor delivers renewed PEMs, copy full chain and private key to the paths Caddy references, fix ownership to the caddy user, then reload.

Validate and reload

caddy validate --config /etc/caddy/Caddyfile
caddy reload --config /etc/caddy/Caddyfile

Verify externally:

HOST=www.example.com
echo | openssl s_client -connect "${HOST}:443" -servername "${HOST}" 2>/dev/null \
  | openssl x509 -noout -dates -serial

How to read the output

Filesystem listings show whether new material landed after ACME or manual install. Recent mtimes with unchanged live serial imply reload did not run or traffic bypasses this instance.

Caddyfile tls lines with absolute paths are authoritative for that site; automatic HTTPS will not override them until removed. JSON config uses equivalent tls certificate loader blocks—grep both sources in GitOps repos.

find output under certificates directories often includes hashed folders per issuer and domain. Do not hand-edit JSON metadata unless recovery documentation permits; prefer fixing configuration and allowing Caddy to rewrite state.

Openssl serial after reload should match the newest file generation for that hostname. Different serials between neighbors on the same server mean each site block owns distinct paths or issuers.

Common mistakes

Renewing via certbot into /etc/letsencrypt/live while site blocks still point at copied PEMs in /etc/ssl/caddy. Mounting read-only volumes in Kubernetes so automatic HTTPS cannot append renewals.

Assuming the default data path on a laptop matches production Helm values. Running multiple Caddy instances sharing one data directory without coordinated locking.

Documenting only the Caddyfile path while production uses JSON from an API feed. Forgetting to update both active and standby nodes in active-passive pairs.

Treating admin-only certificates stored beside public assets as customer-facing when monitoring alerts fire.

Configuration management pipelines that render Caddy JSON from templates should version the data directory path in the same pull request as site label changes. Drift between rendered API config and on-disk mounts is a frequent source of renewal files landing where no running process reads them.

Disaster recovery exercises that restore Caddyfiles but not data directories recreate expired automatic HTTPS state on cold sites even when DNS already points at the DR region. Backup policies must include the full persistence backing ACME accounts.

When platform engineering adopts GitOps for Caddy, document who owns the data plane versus the control plane. Commits that add hostnames without storage provisioning look successful in CI while production never obtains until someone notices path errors in logs.

Partnership microsites sometimes receive manual commercial certificates dropped into generic paths that other teams rotate quarterly. Tag paths in service catalogs so caddy ssl certificate path documentation stays tied to billing owners.

Finance teams auditing OV purchases should compare vendor notAfter with openssl live checks after install. Path documentation in tickets prevents arguing whether finance or infrastructure missed a handoff.

When to use automation

Inventory spreadsheets of caddy ssl certificate path values go stale the week someone adds a manual tls override for a marketing microsite. Monitor live TLS presentation per hostname instead of only mtimes on a shared data mount.

SSLdays performs external handshakes on the names end users request, independent of where files live on disk. Alerts at 30, 14, 7, and 1 days give time to align path configuration and reload discipline before expiry. Pair TLS checks with RDAP domain expiration for names that also depend on registrar health.

Run a live check after every path or storage change, then add the hostname to scheduled monitoring via /register. Paid plans add Slack and Discord webhooks when hourly checks fit operational cadence.

Frequently asked questions

Can I point automatic storage elsewhere?

Yes via configuration and environment variables documented for your distribution. Ensure backups cover the new location before decommissioning old disks.

Should certbot and Caddy share paths?

Avoid two ACME clients fighting for the same names. Pick one automation story; if certbot writes PEMs, reference those paths explicitly or switch fully to automatic HTTPS.

How do I see which cert loads for a site?

Use admin API config dumps where enabled, or openssl with the public servername. Logs during reload show loaded certificate names at debug level.

Do path changes require restart?

Reload is usually sufficient. Restart if reload fails or binary plugins change; document impact on long-lived connections for customer-facing services.

Monitor this hostname on a schedule

Live certificate checks and renewal reminders — not guesswork from PEM files.