> ## Documentation Index
> Fetch the complete documentation index at: https://mintlify.com/caddyserver/caddy/llms.txt
> Use this file to discover all available pages before exploring further.

# Certificate Management

> Loading, automating, and managing TLS certificates in Caddy

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

<ParamField path="automate" type="array of strings">
  Automatically manages certificates for the specified names, including obtaining and renewing certificates.

  <Info>
    This is a special certificate loader that uses Caddy's automation features rather than loading certificates manually.
  </Info>

  Certificates are managed according to their matching automation policy configured elsewhere in the TLS app.
</ParamField>

#### Example

```json theme={null}
{
  "apps": {
    "tls": {
      "certificates": {
        "automate": ["example.com", "*.example.com", "api.example.com"]
      }
    }
  }
}
```

### File Loader

<ParamField path="load_files" type="array">
  Loads certificates and their associated keys from disk.

  Each entry specifies a certificate/key pair with optional tags.
</ParamField>

<ParamField path="certificate" type="string" required>
  Path to the certificate (public key) file.
</ParamField>

<ParamField path="key" type="string" required>
  Path to the private key file.
</ParamField>

<ParamField path="format" type="string" default="pem">
  The format of the cert and key.

  Currently only `pem` is supported.
</ParamField>

<ParamField path="tags" type="array">
  Arbitrary values to associate with this certificate.

  <Info>
    Useful when you want to select a particular certificate when there may be multiple valid candidates.
  </Info>
</ParamField>

#### Example

```json theme={null}
{
  "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"]
          }
        ]
      }
    }
  }
}
```

<Warning>
  Encrypted private keys are not supported. Please decrypt the key first.
</Warning>

### Folder Loader

Loads all certificate pairs from a directory:

```json theme={null}
{
  "apps": {
    "tls": {
      "certificates": {
        "load_folders": ["/path/to/cert/directory"]
      }
    }
  }
}
```

<Note>
  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`).
</Note>

### PEM Loader

Loads certificates from inline PEM text:

```json theme={null}
{
  "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:

```json theme={null}
{
  "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.

<ParamField path="cache.capacity" type="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.
</ParamField>

### Example

```json theme={null}
{
  "apps": {
    "tls": {
      "cache": {
        "capacity": 5000
      }
    }
  }
}
```

## OCSP Stapling

Caddy automatically staples OCSP responses for all qualifying certificates.

<ParamField path="disable_ocsp_stapling" type="boolean" default="false">
  Disables OCSP stapling for manually-managed certificates only.

  <Warning>
    Disabling OCSP stapling puts clients at greater risk, reduces their privacy, and usually lowers client performance. NOT recommended unless you can justify the costs.
  </Warning>

  To configure OCSP stapling for automated certificates, use an automation policy instead.
</ParamField>

### Example

```json theme={null}
{
  "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

```json theme={null}
{
  "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:

```json theme={null}
{
  "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": "admin@example.com"}
            ]
          }
        ]
      }
    }
  }
}
```

## Caddyfile Configuration

### Automated Certificates

```caddyfile theme={null}
example.com {
  # Certificate is automatically obtained and managed
  respond "Hello, World!"
}
```

### Manual Certificate Loading

```caddyfile theme={null}
example.com {
  tls /path/to/cert.pem /path/to/key.pem
  respond "Hello, World!"
}
```

### Self-Signed Certificate

```caddyfile theme={null}
example.com {
  tls internal
  respond "Development Server"
}
```

### Disable Automatic HTTPS

```caddyfile theme={null}
http://example.com {
  respond "HTTP only"
}
```

### Global Certificate Loading

```caddyfile theme={null}
{
  cert_issuer acme {
    email admin@example.com
  }
}

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

<Info>
  Caddy automatically renews managed certificates before they expire. Default renewal window is 1/3 of the certificate's lifetime.
</Info>

**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:

```bash theme={null}
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

```json theme={null}
{
  "storage": {
    "module": "file_system",
    "root": "/var/lib/caddy"
  }
}
```

## Best Practices

<Warning>
  **Manual Certificates:** Must be renewed manually before expiration. Set up monitoring and alerts.
</Warning>

<Info>
  **Automated Certificates:** Preferred for production. Let Caddy handle the entire lifecycle.
</Info>

<Note>
  **Certificate Cache:** The default capacity (10,000) is suitable for most deployments. Increase if managing many domains.
</Note>

<Warning>
  **Private Keys:** Never commit private keys to version control. Use secure storage and proper file permissions (0600).
</Warning>

## 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:

```json theme={null}
{
  "automation": {
    "policies": [
      {
        "get_certificate": [
          {
            "via": "custom_manager",
            "config": {}
          }
        ]
      }
    ]
  }
}
```

<Warning>EXPERIMENTAL: Certificate managers API is experimental and subject to change.</Warning>
