AgentSkillsCN

caddy-reverse-proxy

Caddy Web 服务器配置:用于反向代理与自动 HTTPS。当您遇到以下场景时,可优先选用此技能: (1) 编写 Caddyfile 配置,搭建反向代理环境; (2) 通过 Let's Encrypt 自动配置 HTTPS; (3) 通过 DNS 挑战设置通配符证书; (4) 将 Caddy 与 Docker 容器集成(在同一网络或宿主机上运行服务); (5) 配置请求匹配器、处理块与路由规则; (6) 设置负载均衡与健康检查机制; (7) 排查 TLS、上游连接或配置相关的问题; (8) 配置头部操作(header_up、header_down)。

SKILL.md
--- frontmatter
name: caddy-reverse-proxy
description: |
  Caddy web server configuration for reverse proxy and automatic HTTPS. Use when:
  (1) Writing Caddyfile configurations for reverse proxy setups
  (2) Configuring automatic HTTPS with Let's Encrypt
  (3) Setting up wildcard certificates with DNS challenge
  (4) Integrating Caddy with Docker containers (same network or host services)
  (5) Configuring request matchers, handle blocks, and routing patterns
  (6) Setting up load balancing and health checks
  (7) Troubleshooting TLS, upstream connectivity, or configuration issues
  (8) Configuring header manipulation (header_up, header_down)

Caddy Reverse Proxy

Caddy is a web server with automatic HTTPS. It obtains and renews certificates automatically, redirects HTTP to HTTPS, and provides a simple configuration syntax.

Quick Reference

TaskSyntax
Basic proxyreverse_proxy backend:8080
Multiple upstreamsreverse_proxy node1:80 node2:80
Path routinghandle /api/* { reverse_proxy api:8080 }
Strip path prefixhandle_path /api/* { reverse_proxy api:8080 }
Set request headerheader_up Host localhost
Remove response headerheader_down -Server
Wildcard certtls { dns cloudflare {env.CF_API_TOKEN} }
Reload configcaddy reload --config /etc/caddy/Caddyfile

Basic Patterns

Simple Reverse Proxy

code
example.com {
    reverse_proxy backend:8080
}

Multiple Sites

code
app.example.com {
    reverse_proxy app:3000
}

api.example.com {
    reverse_proxy api:8080
}

Path-Based Routing

code
example.com {
    handle /api/* {
        reverse_proxy api:8080
    }
    handle {
        reverse_proxy frontend:3000
    }
}

Strip Path Prefix

code
example.com {
    handle_path /api/* {
        reverse_proxy api:8080  # /api/users → /users
    }
}

Header Manipulation

code
example.com {
    reverse_proxy backend:8080 {
        # Set Host header (required by some backends)
        header_up Host localhost

        # Add client IP
        header_up X-Real-IP {remote_host}

        # Remove sensitive header
        header_up -Authorization

        # Remove server identity from response
        header_down -Server
    }
}

Docker Integration

Proxy to Container (Same Network)

yaml
# docker-compose.yml
services:
  caddy:
    image: caddy:2-alpine
    ports:
      - "80:80"
      - "443:443"
    volumes:
      - ./Caddyfile:/etc/caddy/Caddyfile:ro
      - caddy_data:/data
    networks:
      - web

  app:
    image: myapp
    networks:
      - web
    expose:
      - "8080"
code
# Caddyfile - use container name as hostname
example.com {
    reverse_proxy app:8080
}

Proxy to Host Service

yaml
services:
  caddy:
    extra_hosts:
      - "host.docker.internal:host-gateway"
code
example.com {
    reverse_proxy host.docker.internal:8080
}

TLS Configuration

Automatic (Default)

Caddy automatically obtains certificates when:

  • Domain DNS points to server
  • Ports 80/443 accessible

Wildcard Certificates

Requires DNS provider plugin:

code
*.example.com {
    tls {
        dns cloudflare {env.CF_API_TOKEN}
    }

    @app1 host app1.example.com
    handle @app1 {
        reverse_proxy app1:8080
    }

    @app2 host app2.example.com
    handle @app2 {
        reverse_proxy app2:8080
    }
}

Internal/Development

code
localhost {
    tls internal
    reverse_proxy app:8080
}

Request Matchers

code
# Path matching
@api path /api/*

# Header matching
@websocket header Connection *Upgrade*

# Method matching
@post method POST

# Combined (AND logic)
@api_post {
    path /api/*
    method POST
}

# Use matcher
handle @api {
    reverse_proxy api:8080
}

Load Balancing

code
example.com {
    reverse_proxy node1:80 node2:80 node3:80 {
        lb_policy round_robin
        health_uri /health
        health_interval 30s
    }
}

Common Configurations

Security Headers

code
(security) {
    header {
        Strict-Transport-Security "max-age=31536000; includeSubDomains"
        X-Content-Type-Options nosniff
        X-Frame-Options SAMEORIGIN
        Referrer-Policy strict-origin-when-cross-origin
    }
}

example.com {
    import security
    reverse_proxy backend:8080
}

www Redirect

code
www.example.com {
    redir https://example.com{uri} permanent
}

SPA (Single Page App)

code
example.com {
    root * /srv
    try_files {path} /index.html
    file_server
}

gRPC / HTTP/2 Cleartext

code
example.com {
    reverse_proxy h2c://grpc-server:9000
}

Global Options

code
{
    email admin@example.com

    # Use staging for testing
    # acme_ca https://acme-staging-v02.api.letsencrypt.org/directory
}

example.com {
    # site config
}

Reference Files

FileWhen to Read
reverse-proxy.mdLoad balancing, health checks, transport options
caddyfile-syntax.mdMatchers, handle blocks, directives
tls-certificates.mdDNS challenge, wildcards, mTLS
docker-patterns.mdDocker Compose, networks, host access
troubleshooting.mdCommon errors and diagnostics

Common Issues

ProblemSolution
"no upstreams available"Check backend running, same Docker network
"connection refused"Backend binding to 0.0.0.0, not 127.0.0.1
Certificate not obtainedCheck DNS points to server, ports 80/443 open
403 ForbiddenBackend needs header_up Host localhost
WebSocket failsUsually works; check flush_interval -1 for SSE

Verification Commands

bash
# Validate config
caddy validate --config /etc/caddy/Caddyfile

# Format config
caddy fmt --overwrite /etc/caddy/Caddyfile

# Reload (zero-downtime)
caddy reload --config /etc/caddy/Caddyfile

# Debug mode
# Add to global options: { debug }

# Check certificate
openssl s_client -connect example.com:443 -servername example.com

Official Documentation