HTTPS Configuration
Caddy is the first web server to enable HTTPS by default. It automatically obtains and renews certificates from Let’s Encrypt and other ACME CAs.
Automatic HTTPS
HTTPS is enabled automatically for all sites with hostnames:
example.com {
respond "Hello, HTTPS!"
}
Caddy automatically:
- Obtains certificates from Let’s Encrypt
- Renews certificates before expiration
- Staples OCSP responses
- Redirects HTTP to HTTPS
Certificate Automation
Automation Policies
Configure how certificates are obtained and managed:
{
"apps": {
"tls": {
"automation": {
"policies": [
{
"subjects": ["example.com", "*.example.com"],
"issuers": [
{
"module": "acme",
"email": "[email protected]",
"ca": "https://acme-v02.api.letsencrypt.org/directory"
}
],
"renewal_window_ratio": 0.33,
"key_type": "ec256",
"must_staple": false
}
],
"ocsp_interval": "1h",
"renew_interval": "10m"
}
}
}
}
Key Types
Supported key types:
ec256 - ECDSA P-256 (default, recommended)
ec384 - ECDSA P-384
rsa2048 - RSA 2048-bit
rsa4096 - RSA 4096-bit
ed25519 - Ed25519
ECDSA keys (ec256) provide better performance and smaller certificate sizes compared to RSA.
Certificate Issuers
Let’s Encrypt
Default production CA:
tls {
issuer acme {
ca https://acme-v02.api.letsencrypt.org/directory
email [email protected]
}
}
ZeroSSL
Alternative CA with longer validity:
Internal Certificates
For development or internal services:
localhost {
tls internal
}
# Or for specific domains
intranet.local {
tls internal {
ca internal_ca
}
}
On-Demand TLS
Obtain certificates during TLS handshakes:
{
"apps": {
"tls": {
"automation": {
"on_demand": {
"ask": "https://api.example.com/check-domain",
"rate_limit": {
"interval": "1m",
"burst": 5
}
},
"policies": [
{
"on_demand": true
}
]
}
}
}
}
On-Demand TLS is powerful but must be protected with rate limits or an ask endpoint to prevent abuse. Without protections, attackers could trigger unlimited certificate requests.
Permission Module
Validate domains before issuing certificates:
{
"on_demand": {
"permission": {
"module": "http",
"endpoint": "https://api.example.com/check-domain?domain={domain}"
}
}
}
Manual Certificates
Load from Files
{
"apps": {
"tls": {
"certificates": {
"load_files": [
{
"certificate": "/path/to/cert.pem",
"key": "/path/to/key.pem"
}
]
}
}
}
}
Load from Folder
Automatically load all certificates from a directory:
{
"apps": {
"tls": {
"certificates": {
"load_folders": ["/path/to/certs"]
}
}
}
}
DNS Challenge
Use DNS-01 challenge for wildcard certificates or when HTTP-01 is unavailable:
{
"issuer": {
"module": "acme",
"challenges": {
"dns": {
"provider": {
"name": "cloudflare",
"api_token": "{env.CLOUDFLARE_API_TOKEN}"
}
}
}
}
}
TLS Settings
Connection Policy
Configure TLS settings per hostname:
{
"apps": {
"tls": {
"connection_policies": [
{
"match": {
"sni": ["example.com"]
},
"protocol_min": "tls1.2",
"protocol_max": "tls1.3",
"cipher_suites": [
"TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384",
"TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384"
],
"curves": ["x25519", "secp256r1"],
"alpn": ["h2", "http/1.1"]
}
]
}
}
}
Client Authentication
Require client certificates (mutual TLS):
example.com {
tls {
client_auth {
mode require_and_verify
trusted_ca_cert_file /path/to/ca.pem
}
}
}
Certificate Storage
File System (Default)
Certificates are stored in:
- Linux:
$XDG_DATA_HOME/caddy or $HOME/.local/share/caddy
- macOS:
$HOME/Library/Application Support/Caddy
- Windows:
%APPDATA%\Caddy
Custom Storage
Use different storage backends:
{
"storage": {
"module": "file_system",
"root": "/custom/path/to/storage"
}
}
Session Tickets
Configure session ticket rotation:
{
"apps": {
"tls": {
"session_tickets": {
"key_source": {
"module": "standard"
},
"rotation_interval": "24h",
"max_keys": 4,
"disabled": false
}
}
}
}
OCSP Stapling
Caddy automatically staples OCSP responses. Configure check intervals:
{
"automation": {
"ocsp_interval": "1h",
"policies": [
{
"disable_ocsp_stapling": false
}
]
}
}
Complete Example
# Main site with automatic HTTPS
example.com {
tls [email protected] {
# Use Let's Encrypt
issuer acme {
ca https://acme-v02.api.letsencrypt.org/directory
}
# Use ECDSA key
key_type ec256
# TLS settings
protocols tls1.2 tls1.3
# Require client certificates
client_auth {
mode request
trusted_ca_cert_file /path/to/client-ca.pem
}
}
respond "Secure site"
}
# Wildcard with DNS challenge
*.api.example.com {
tls {
dns cloudflare {env.CLOUDFLARE_API_TOKEN}
}
reverse_proxy backend:8080
}
# Internal development site
localhost {
tls internal
file_server
}
Best Practices
Use ECDSA keys - Better performance than RSA
Enable OCSP stapling - Enabled by default
Keep TLS 1.2+ only - Disable older protocols
Monitor certificate expiration - Caddy renews automatically at 1/3 lifetime remaining
Protect on-demand TLS - Always use rate limits or validation
Caddy checks certificates for renewal every 10 minutes by default. Certificates are renewed when they have about 1/3 of their lifetime remaining.