Skip to main content
โšก Calmops

Caddy Web Server: Modern HTTPS Everything Server 2026

Introduction

Caddy is a modern, modular web server that stands out for its automatic HTTPS capability and simplicity. Written in Go, Caddy was designed from the ground up to be secure-by-default, automatic, and easy to configure. In 2026, with HTTPS adoption reaching near-universal levels and TLS configuration becoming increasingly complex, Caddy’s philosophy of “HTTPS by default” has never been more relevant.

This comprehensive guide covers Caddy’s unique features, configuration syntax, reverse proxy capabilities, advanced TLS management, and production deployment strategies. Whether you’re seeking a simple development server or a production-grade TLS termination point, Caddy offers a compelling solution.

What is Caddy?

Caddy is an open-source web server with automatic HTTPS written in Go. Its defining characteristic is making TLS configuration effortless while providing all the features expected from a production web server.

Key Features

Automatic HTTPS: Caddy obtains and renews TLS certificates automatically for all sites.

HTTP/3 Support: Native HTTP/3 support out of the box.

Reverse Proxy: Built-in powerful reverse proxy with load balancing and health checks.

FastCGI: Native support for PHP, Python, and other FastCGI applications.

WebSockets: Full WebSocket proxy support.

Markdown Rendering: Serve Markdown files with automatic rendering.

Minimal Configuration: Most sites work with minimal or no configuration.

Installation

Binary Installation

# Download Caddy
curl -o caddy https://getcaddy.com?softcare=tar.gz

# Or use official installer
curl https://getcaddy.com | bash -s personal

# Verify installation
caddy version

Package Managers

# macOS
brew install caddy

# Ubuntu/Debian
sudo apt install -y debian-keyring debian-archive-keyring apt-transport-https
curl -1sLf 'https://dl.cloudsmith.io/public/caddy/stable/gpg.key' | sudo gpg --dearmor -o /usr/share/keyrings/caddy-stable-archive-keyring.gpg
curl -1sLf 'https://dl.cloudsmith.io/public/caddy/stable/debian.deb.txt' | sudo tee /etc/apt/sources.list.d/caddy-stable.list
sudo apt update
sudo apt install caddy

# Docker
docker pull caddy:2

Building from Source

# Install Go
curl -sL https://golang.org/dl/go1.21.linux-amd64.tar.gz | sudo tar -C /usr/local -xzf -

# Clone and build
git clone https://github.com/caddyserver/caddy.git
cd caddy/cmd/caddy/
go install

Configuration

Caddyfile Syntax

Caddy’s configuration format (Caddyfile) is designed for readability:

# Simple static site
example.com {
    root * /var/www
    file_server
}

# Reverse proxy
api.example.com {
    reverse_proxy localhost:8080
}

# With TLS
tls [email protected]

Basic Static Site

example.com {
    # Serve static files from /var/www
    root * /var/www
    
    # Enable static file server
    file_server
    
    # Enable gzip compression
    encode gzip
    
    # Parse HTML templates
    templates
}

Multiple Sites

# Site 1: Static files
www.example.com {
    root * /var/www/frontend
    file_server
    encode gzip
}

# Site 2: API
api.example.com {
    reverse_proxy localhost:3000
}

# Site 3: PHP-FPM
blog.example.com {
    root * /var/www/wordpress
    php_fastcgi localhost:9000
}

Automatic HTTPS

Caddy’s automatic HTTPS is its standout feature.

How It Works

# No configuration needed - HTTPS automatic
example.com {
    root * /var/www
    file_server
}

Caddy will:

  1. Obtain TLS certificate from Let’s Encrypt on first request
  2. Redirect HTTP to HTTPS automatically
  3. Renew certificates 30 days before expiration
  4. Handle OCSP stapling
  5. Support HTTP/3

Custom TLS Configuration

example.com {
    tls {
        dns cloudflare
        protocols tls1.3
        ciphers TLS_AES_256_GCM_SHA384 TLS_CHACHA20_POLY1305_SHA256
    }
    root * /var/www
    file_server
}

TLS with Custom Certificate

example.com {
    tls /etc/ssl/certs/server.crt /etc/ssl/private/server.key
    
    # Or with internal CA
    tls {
        ca /path/to/ca.crt
        ca_root /path/to/ca-root.crt
    }
    
    root * /var/www
    file_server
}

Mutual TLS (mTLS)

example.com {
    tls {
        client_ca /etc/ssl/certs/client-ca.crt
        verify_client_if_given
    }
    
    reverse_proxy localhost:8080
}

Reverse Proxy

Caddy includes a powerful reverse proxy implementation.

Basic Reverse Proxy

example.com {
    reverse_proxy localhost:8080
}

Load Balancing

example.com {
    reverse_proxy {
        to localhost:8080 localhost:8081 localhost:8082
        health_path /health
        health_interval 30s
        health_timeout 5s
        lb_try_duration 5s
    }
}

Load Balancing Methods

example.com {
    # Round robin (default)
    reverse_proxy {
        to backend1:8080 backend2:8080 backend3:8080
    }
    
    # Random
    reverse_proxy {
        to backend1:8080 backend2:8080
        lb_policy random
    }
    
    # IP hash (sticky sessions)
    reverse_proxy {
        to backend1:8080 backend2:8080
        lb_policy ip_hash
    }
    
    # Header-based
    reverse_proxy {
        to backend1:8080 backend2:8080
        lb_policy header X-User-ID
    }
}

Header Manipulation

example.com {
    reverse_proxy localhost:8080 {
        header_up X-Forwarded-For {remote_host}
        header_up X-Forwarded-Proto {scheme}
        header_up X-Real-IP {remote}
        header_up Host {host}
        header_down X-Powered-By "Caddy"
    }
}

WebSocket Proxying

example.com {
    reverse_proxy localhost:8080 {
        header_up Upgrade {>Upgrade}
        header_up Connection {>Connection}
    }
}

FastCGI Support

Caddy has native FastCGI support for PHP, Python, and other languages.

PHP-FPM

example.com {
    root * /var/www
    php_fastcgi localhost:9000
    file_server
}

PHP with Custom Socket

example.com {
    root * /var/www
    php_fastcgi unix//run/php/php8.1-fpm.sock
    encode gzip zstd
    file_server
}

Python WSGI

example.com {
    root * /var/www
    reverse_proxy unix//run/gunicorn.sock {
        header_up Host {host}
    }
}

Advanced Features

URL Rewriting

example.com {
    # Simple rewrite
    rewrite /old /new
    
    # Regex rewrite
    @blog {
        path /blog/*
    }
    rewrite @blog /blog/index.php?p={path}
    
    # Query parameter manipulation
    @old {
        query p=
    }
    redirect @old /new-page
}

Request Matching

example.com {
    # Path matching
    @api {
        path /api/*
    }
    reverse_proxy @api localhost:8080
    
    # Header matching
    @mobile {
        header User-Agent *Mobile*
    }
    reverse_proxy @mobile localhost:8081
    
    # Method matching
    @posts {
        path /posts/*
        method POST PUT DELETE
    }
    reverse_proxy @posts localhost:8082
    
    # Combined matching
    @admin {
        path /admin/*
        header Authorization "Bearer *"
    }
    reverse_proxy @admin localhost:8083
}

Compression

example.com {
    # Automatic compression
    encode {
        gzip
        zstd
    }
    
    # Custom compression levels
    encode gzip 6
    
    # Match specific types
    encode {
        match {
            header Content-Type text/*
            header Content-Type application/json
            header Content-Type application/javascript
        }
        gzip
    }
}

Rate Limiting

example.com {
    # Global rate limit
    rate_limit {
        zone generic {
            key {remote_ip}
            events 100
            window 1s
        }
    }
    
    reverse_proxy localhost:8080
}

Caching Headers

example.com {
    root * /var/www
    file_server
    
    # Set cache headers
    @static {
        path *.css *.js *.ico *.svg *.jpg *.png
    }
    header @static {
        Cache-Control "public, max-age=31536000, immutable"
    }
    
    # Remove headers
    header {
        -X-Powered-By
        -Server
    }
}

Container Deployment

Docker Compose

version: '3.8'

services:
  caddy:
    image: caddy:2
    container_name: caddy
    ports:
      - "80:80"
      - "443:443"
      - "443:443/udp"  # HTTP/3
    volumes:
      - ./Caddyfile:/etc/caddy/Caddyfile:ro
      - ./www:/var/www:ro
      - caddy_data:/data
      - caddy_config:/config
    environment:
      - CADDY_INGRESS_NETWORKS=caddy
    restart: unless-stopped

volumes:
  caddy_data:
  caddy_config:

Docker with Custom Config

docker run -d --name caddy \
  -p 80:80 \
  -p 443:443 \
  -p 443:443/udp \
  -v $(pwd)/Caddyfile:/etc/caddy/Caddyfile \
  -v $(pwd)/site:/var/www \
  -v caddy_data:/data \
  caddy:2

Production Configuration

Production Caddyfile

# Global options
{
    admin off
    email [email protected]
    ocsp_stapling off
    log {
        output file /var/log/caddy/access.log
        format console
    }
}

# Main site
example.com {
    root * /var/www
    file_server
    
    encode {
        gzip
    }
    
    # Security headers
    header {
        Strict-Transport-Security "max-age=31536000; includeSubDomains"
        X-Content-Type-Options "nosniff"
        X-Frame-Options "DENY"
        X-XSS-Protection "1; mode=block"
        Referrer-Policy "strict-origin-when-cross-origin"
        -X-Powered-By
    }
    
    # Handle .php files
    php_fastcgi unix//run/php/php8.1-fpm.sock
    
    # Log format
    log {
        output file /var/log/caddy/example.com.log
    }
}

# API subdomain
api.example.com {
    reverse_proxy localhost:3000 {
        header_up X-Real-IP {remote}
        header_up X-Forwarded-For {remote_host}
        header_up X-Forwarded-Proto {scheme}
    }
    
    # Rate limiting
    rate_limit {
        zone api {
            key {remote_ip}
            events 1000
            window 1s
        }
    }
}

# Admin panel (internal only)
admin.example.com {
    internal
    reverse_proxy localhost:8080
}

Systemd Service

[Unit]
Description=Caddy Web Server
Documentation=https://caddyserver.com/docs/
After=network.target network-online.target
Requires=network-online.target

[Service]
Type=notify
User=caddy
Group=caddy
ExecStart=/usr/bin/caddy run --environ --config /etc/caddy/Caddyfile
ExecReload=/usr/bin/caddy reload --config /etc/caddy/Caddyfile --force
TimeoutStopSec=5s
LimitNOFILE=1048576
LimitNPROC=512
PrivateTmp=true
ProtectSystem=full
AmbientCapabilities=CAP_NET_BIND_SERVICE

[Install]
WantedBy=multi-user.target

Performance Tuning

Connection Limits

{
    servers {
        read_header_timeout 10s
        read_timeout 60s
        write_timeout 60s
        idle_timeout 5m
        max_header_bytes 32768
    }
}

HTTP/3 Configuration

{
    servers {
        protocol {
            experimental_http3
        }
    }
}

Go Runtime Tuning

# Set GOMAXPROCS
GOMAXPROCS=4 caddy run

# Memory tuning
GOGC=100 caddy run

Monitoring

Metrics Endpoint

example.com {
    metrics /metrics
}

Structured Logging

example.com {
    log {
        output file /var/log/caddy/access.log
        format json {
            time_format "iso8601"
        }
    }
}

Best Practices

Security

  • Use TLS 1.3 minimum
  • Enable HSTS headers
  • Remove sensitive headers
  • Configure proper CSP headers
  • Use internal routes for admin

Reliability

  • Configure health checks for proxies
  • Set appropriate timeouts
  • Use multiple backend servers
  • Enable request buffering for large uploads

Performance

  • Enable HTTP/3
  • Use compression
  • Configure proper cache headers
  • Monitor connection counts

Configuration

  • Use Caddyfile for simplicity
  • Version control configurations
  • Test configurations before deployment
  • Use includes for organization

Conclusion

Caddy web server represents a paradigm shift in web server configuration, making HTTPS and TLS management effortless while providing all the features needed for production deployments. Its automatic HTTPS, simple configuration syntax, and built-in reverse proxy capabilities make it an excellent choice for developers and operations teams alike.

Whether you’re running a simple static site, a complex multi-service architecture, or anything in between, Caddy’s philosophy of sensible defaults and automatic security provides an excellent foundation. As we move further into 2026 with increasingly complex security requirements, Caddy’s “HTTPS by default” approach positions it as the web server for the modern internet.

Resources

Comments