Skip to main content
Caddy provides multiple ways to load and manage TLS certificates, from fully automated ACME to manual file loading.

Certificate Loaders

Certificate loaders are modules that load certificates into Caddy’s in-memory cache. All loaded certificates are pooled together and may be used to complete TLS handshakes for relevant server names (SNI).

Automate Loader

automate
array of strings
Automatically manages certificates for the specified names, including obtaining and renewing certificates.
This is a special certificate loader that uses Caddy’s automation features rather than loading certificates manually.
Certificates are managed according to their matching automation policy configured elsewhere in the TLS app.

Example

{
  "apps": {
    "tls": {
      "certificates": {
        "automate": ["example.com", "*.example.com", "api.example.com"]
      }
    }
  }
}

File Loader

load_files
array
Loads certificates and their associated keys from disk.Each entry specifies a certificate/key pair with optional tags.
certificate
string
required
Path to the certificate (public key) file.
key
string
required
Path to the private key file.
format
string
default:"pem"
The format of the cert and key.Currently only pem is supported.
tags
array
Arbitrary values to associate with this certificate.
Useful when you want to select a particular certificate when there may be multiple valid candidates.

Example

{
  "apps": {
    "tls": {
      "certificates": {
        "load_files": [
          {
            "certificate": "/etc/ssl/certs/example.com.pem",
            "key": "/etc/ssl/private/example.com.key",
            "tags": ["production"]
          },
          {
            "certificate": "/etc/ssl/certs/wildcard.example.com.pem",
            "key": "/etc/ssl/private/wildcard.example.com.key",
            "tags": ["wildcard", "production"]
          }
        ]
      }
    }
  }
}
Encrypted private keys are not supported. Please decrypt the key first.

Folder Loader

Loads all certificate pairs from a directory:
{
  "apps": {
    "tls": {
      "certificates": {
        "load_folders": ["/path/to/cert/directory"]
      }
    }
  }
}
Certificate and key files should be in the same directory. Files are paired by matching names (e.g., example.com.crt with example.com.key).

PEM Loader

Loads certificates from inline PEM text:
{
  "apps": {
    "tls": {
      "certificates": {
        "load_pem": [
          {
            "certificate": "-----BEGIN CERTIFICATE-----\n...\n-----END CERTIFICATE-----",
            "key": "-----BEGIN PRIVATE KEY-----\n...\n-----END PRIVATE KEY-----",
            "tags": ["embedded"]
          }
        ]
      }
    }
  }
}

Storage Loader

Loads certificates from Caddy’s configured storage:
{
  "apps": {
    "tls": {
      "certificates": {
        "load_storage": [
          {
            "key": "certificates/example.com/example.com.crt",
            "tags": ["from-storage"]
          }
        ]
      }
    }
  }
}

Certificate Cache

Caddy maintains an in-memory certificate cache for fast TLS handshakes.
cache.capacity
integer
default:"10000"
Maximum number of certificates to allow in the cache.If reached, certificates will be randomly evicted to make room for new ones.

Example

{
  "apps": {
    "tls": {
      "cache": {
        "capacity": 5000
      }
    }
  }
}

OCSP Stapling

Caddy automatically staples OCSP responses for all qualifying certificates.
disable_ocsp_stapling
boolean
default:"false"
Disables OCSP stapling for manually-managed certificates only.
Disabling OCSP stapling puts clients at greater risk, reduces their privacy, and usually lowers client performance. NOT recommended unless you can justify the costs.
To configure OCSP stapling for automated certificates, use an automation policy instead.

Example

{
  "apps": {
    "tls": {
      "disable_ocsp_stapling": false
    }
  }
}

Certificate Tags

Tags allow you to associate arbitrary metadata with certificates and select specific certificates during handshakes.

Use Cases

  • Differentiate between production and staging certificates
  • Select certificates based on environment
  • Route to specific certificates based on custom logic

Example with Selection

{
  "apps": {
    "tls": {
      "certificates": {
        "load_files": [
          {
            "certificate": "/certs/prod.pem",
            "key": "/certs/prod.key",
            "tags": ["production", "ecc"]
          },
          {
            "certificate": "/certs/staging.pem",
            "key": "/certs/staging.key",
            "tags": ["staging"]
          }
        ]
      }
    },
    "http": {
      "servers": {
        "srv0": {
          "tls_connection_policies": [
            {
              "certificate_selection": {
                "any_tag": ["production"]
              }
            }
          ]
        }
      }
    }
  }
}

Mixed Manual and Automated

You can combine manual certificate loading with automated management:
{
  "apps": {
    "tls": {
      "certificates": {
        "automate": ["example.com", "www.example.com"],
        "load_files": [
          {
            "certificate": "/etc/ssl/special-cert.pem",
            "key": "/etc/ssl/special-key.pem",
            "tags": ["manual"]
          }
        ]
      },
      "automation": {
        "policies": [
          {
            "subjects": ["example.com", "www.example.com"],
            "issuers": [
              {"module": "acme", "email": "[email protected]"}
            ]
          }
        ]
      }
    }
  }
}

Caddyfile Configuration

Automated Certificates

example.com {
  # Certificate is automatically obtained and managed
  respond "Hello, World!"
}

Manual Certificate Loading

example.com {
  tls /path/to/cert.pem /path/to/key.pem
  respond "Hello, World!"
}

Self-Signed Certificate

example.com {
  tls internal
  respond "Development Server"
}

Disable Automatic HTTPS

http://example.com {
  respond "HTTP only"
}

Global Certificate Loading

{
  cert_issuer acme {
    email [email protected]
  }
}

example.com {
  respond "Hello"
}

Certificate Lifecycle

Obtaining

  1. Automated (ACME)
    • Certificate requested from CA during startup or on-demand
    • ACME challenges completed automatically
    • Certificate stored in configured storage
  2. Manual
    • Certificate loaded from file or storage
    • No automatic management
    • Must be manually renewed before expiration

Renewal

Caddy automatically renews managed certificates before they expire. Default renewal window is 1/3 of the certificate’s lifetime.
Renewal Process:
  1. Certificate monitored for expiration
  2. Renewal attempted when renewal window is reached
  3. If successful, old certificate replaced with new one
  4. If failed, retries with exponential backoff
Renewal Window Example:
  • 90-day certificate: Renews around day 60 (30 days before expiration)
  • 12-hour certificate: Renews around hour 8 (4 hours before expiration)

Revocation

Revoke a certificate using the Caddy API:
curl -X POST http://localhost:2019/pki/ca/local/certificates/revoke \
  -H "Content-Type: application/json" \
  -d '{"serial": "certificate-serial-number"}'

Storage

Certificates are stored in Caddy’s configured storage backend:
  • Default: File system at $HOME/.local/share/caddy or $XDG_DATA_HOME/caddy
  • Alternatives: Consul, DynamoDB, S3, Azure, etc.

Custom Storage

{
  "storage": {
    "module": "file_system",
    "root": "/var/lib/caddy"
  }
}

Best Practices

Manual Certificates: Must be renewed manually before expiration. Set up monitoring and alerts.
Automated Certificates: Preferred for production. Let Caddy handle the entire lifecycle.
Certificate Cache: The default capacity (10,000) is suitable for most deployments. Increase if managing many domains.
Private Keys: Never commit private keys to version control. Use secure storage and proper file permissions (0600).

Troubleshooting

Certificate Not Loading

  1. Check file paths are absolute and accessible
  2. Verify file permissions (Caddy must be able to read them)
  3. Ensure certificate and key match
  4. Check logs for detailed error messages

ACME Challenge Failures

  1. Verify DNS points to your server
  2. Ensure ports 80 (HTTP) or 443 (TLS-ALPN) are accessible
  3. For DNS challenge, verify DNS provider credentials
  4. Check CA rate limits (use staging for testing)

OCSP Stapling Issues

  1. Ensure OCSP responder URL is accessible
  2. Check network connectivity and firewall rules
  3. Verify certificate chain is complete
  4. Review OCSP override configuration if customized

Advanced: Certificate Managers

For advanced use cases, implement custom certificate managers to integrate with external certificate management systems:
{
  "automation": {
    "policies": [
      {
        "get_certificate": [
          {
            "via": "custom_manager",
            "config": {}
          }
        ]
      }
    ]
  }
}
EXPERIMENTAL: Certificate managers API is experimental and subject to change.

Build docs developers (and LLMs) love