强曰为道
与天地相似,故不违。知周乎万物,而道济天下,故不过。旁行而不流,乐天知命,故不忧.
文档目录

Caddy 从入门到精通 / 10 - 高级主题 / Advanced Topics

高级主题 / Advanced Topics

本章覆盖 Caddy 在生产环境中的高级使用场景:集群、性能调优、插件开发、监控、安全加固等。

This chapter covers advanced Caddy usage in production: clustering, performance tuning, plugin development, monitoring, and security hardening.


🟢 基础 / Basics — 性能调优入门 / Performance Basics

Caddy 的默认性能

Caddy 开箱即用的性能已经很好,通常不需要像 Nginx 那样大量调优。但了解基本配置仍然重要。

工作线程数

Caddy 使用 Go 的 goroutine 模型,不需要手动设置 worker 数量。Go runtime 会自动管理:

# 查看 GOMAXPROCS(默认 = CPU 核数)
docker exec caddy env | grep GOMAXPROCS

如需限制:

environment:
  - GOMAXPROCS=4

连接限制

{
    # 限制最大连接数(JSON API 层面)
}

example.com {
    reverse_proxy localhost:3000 {
        transport http {
            max_idle_conns        100
            max_idle_conns_per_host 10
            idle_conn_timeout     90s
        }
    }
}

日志对性能的影响

同步日志写入会成为瓶颈。建议使用异步日志或减少日志粒度:

{
    log default {
        output file /var/log/caddy/access.log {
            roll_size 100mb
            roll_keep 5
        }
        # 只记录关键字段
        format filter {
            wrap json
            fields {
                request>remote_ip ip_mask {
                    ipv4 24
                    ipv6 32
                }
                request>uri query {
                    replace session_id REDACTED
                }
            }
        }
    }
}

🟡 进阶 / Intermediate

集群模式 / Clustering

Caddy 本身不是原生集群软件,但可以通过共享存储实现多实例协同:

证书共享

多台 Caddy 实例共享同一个 ACME 状态,避免重复申请证书:

方案一:NFS / GlusterFS 共享 /data
方案二:Redis / Consul 后端存储(需插件)
方案三:rsync 定期同步

NFS 共享示例:

# 所有 Caddy 实例挂载同一个 NFS
services:
  caddy1:
    volumes:
      - /nfs/caddy/data:/data
  caddy2:
    volumes:
      - /nfs/caddy/data:/data

⚠️ 注意并发锁:多个实例同时续期证书可能产生竞争。Caddy 内部有文件锁机制,在 NFS 上需要支持 fcntl 锁。

配置同步

# 主节点修改后推送到所有节点
for host in caddy2 caddy3; do
    scp Caddyfile root@${host}:/etc/caddy/Caddyfile
    ssh root@${host} "caddy reload --config /etc/caddy/Caddyfile"
done

或使用 etcd / Consul 做配置中心:

[配置中心 (etcd)]
    │
    ├── caddy1 watches key
    ├── caddy2 watches key
    └── caddy3 watches key

Prometheus 监控集成

Caddy 内置 metrics 支持(需要编译时包含):

xcaddy build --with github.com/mholt/caddy-events-prometheus
{
    admin off
}

:2019 {
    metrics /metrics
}

example.com {
    reverse_proxy localhost:3000
}

关键 metrics:

  • caddy_http_requests_total — 请求计数
  • caddy_http_request_duration_seconds — 请求延迟
  • caddy_http_response_status_count — 状态码统计

Grafana Dashboard:ID: 19127

日志接入 ELK / Loki

JSON 格式 → Filebeat → Elasticsearch:

{
    log {
        format json
        output file /var/log/caddy/access.log
    }
}
# filebeat.yml
filebeat.inputs:
  - type: log
    paths:
      - /var/log/caddy/access.log
    json.keys_under_root: true

output.elasticsearch:
  hosts: ["http://elasticsearch:9200"]

JSON 格式 → Promtail → Loki:

# promtail-config.yml
scrape_configs:
  - job_name: caddy
    static_configs:
      - targets: [localhost]
        labels:
          job: caddy
          __path__: /var/log/caddy/access.log
    pipeline_stages:
      - json:
          expressions:
            status: status
            method: request>method
      - labels:
          status:
          method:

安全加固清单

{
    # 禁用管理 API(生产环境推荐)
    admin off
}

example.com {
    # 安全头
    header {
        Strict-Transport-Security "max-age=63072000; includeSubDomains; preload"
        X-Content-Type-Options "nosniff"
        X-Frame-Options "DENY"
        Referrer-Policy "strict-origin-when-cross-origin"
        Permissions-Policy "camera=(), microphone=(), geolocation=()"
        Content-Security-Policy "default-src 'self'; script-src 'self'; style-src 'self' 'unsafe-inline'"
        -Server
        -X-Powered-By
    }

    # 限制请求体大小
    request_body {
        max_size 10MB
    }

    # 隐藏文件拒绝
    @hidden path */.*
    respond @hidden 403

    reverse_proxy localhost:3000
}

🔴 高级 / Advanced

插件开发 / Plugin Development

Caddy 插件就是 Go module,只需实现特定接口并注册:

package myhandler

import (
    "net/http"
    "github.com/caddyserver/caddy/v2"
    "github.com/caddyserver/caddy/v2/caddyconfig/caddyfile"
    "github.com/caddyserver/caddy/v2/modules/caddyhttp"
)

func init() {
    caddy.RegisterModule(MyHandler{})
}

type MyHandler struct {
    Message string `json:"message,omitempty"`
}

func (MyHandler) CaddyModule() caddy.ModuleInfo {
    return caddy.ModuleInfo{
        ID:  "http.handlers.myhandler",
        New: func() caddy.Module { return new(MyHandler) },
    }
}

// UnmarshalCaddyfile 实现 Caddyfile 解析
func (h *MyHandler) UnmarshalCaddyfile(d *caddyfile.Dispenser) error {
    for d.Next() {
        if !d.Args(&h.Message) {
            return d.ArgErr()
        }
    }
    return nil
}

func (h MyHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) error {
    w.Write([]byte(h.Message))
    return nil
}

// 接口断言
var _ caddyhttp.MiddlewareHandler = (*MyHandler)(nil)

使用 xcaddy 编译:

xcaddy build --with github.com/you/caddy-myhandler=./myhandler

Caddyfile 使用:

example.com {
    myhandler "Hello from custom plugin!"
}

插件类型一览

接口用途
caddyhttp.MiddlewareHandlerHTTP 中间件
caddyhttp.HandlerHTTP 处理器
caddy.Validator配置验证
caddy.Provisioner初始化逻辑
caddy.Cleaner清理逻辑
caddyfile.UnmarshalerCaddyfile 解析
certmagic.Issuer自定义证书签发
certmagic.Storage自定义证书存储

自定义存储后端(Redis 存储证书)

package redisstorage

import (
    "github.com/caddyserver/certmagic"
)

type RedisStorage struct {
    Addr     string `json:"addr"`
    Password string `json:"password"`
    DB       int    `json:"db"`
}

func (s *RedisStorage) Store(ctx context.Context, key string, value []byte) error {
    // 存储到 Redis
}

func (s *RedisStorage) Load(ctx context.Context, key string) ([]byte, error) {
    // 从 Redis 读取
}

// ... 实现其他 certmagic.Storage 接口方法

这样多台 Caddy 实例可以共享同一套证书存储,完美解决集群问题。

调试技巧

开启 debug 日志:

{
    debug
}

查看完整 JSON 配置:

curl http://localhost:2019/config/ | jq .

追踪 TLS 握手:

caddy run --config Caddyfile 2>&1 | grep -i tls

使用 pprof 性能分析:

{
    admin localhost:2019
}
# CPU profile
go tool pprof http://localhost:2019/debug/pprof/profile?seconds=30

# Heap profile
go tool pprof http://localhost:2019/debug/pprof/heap

从 Nginx 迁移 / Migration from Nginx

NginxCaddy
server {}example.com {}
listen 80(自动处理)
server_name站点块名
rootroot * /path
location / {}handle / {}
proxy_passreverse_proxy
ssl_certificate(自动处理)
try_filestry_files
rewriterewriteuri
gzip onencode gzip
error_pagehandle_errors
if (!-f $request_filename)@not_file not file

高流量场景参考配置

{
    # 关闭管理 API
    admin off

    # 日志优化
    log {
        format json {
            time_format "2006-01-02T15:04:05Z07:00"
        }
        output file /var/log/caddy/access.log {
            roll_size 200mb
            roll_keep 5
        }
    }
}

example.com {
    # 安全头
    header {
        Strict-Transport-Security "max-age=63072000; includeSubDomains; preload"
        X-Content-Type-Options "nosniff"
        -Server
    }

    # 压缩
    encode gzip zstd

    # 静态资源长缓存
    @static path *.css *.js *.png *.jpg *.gif *.svg *.woff2 *.ico
    header @static Cache-Control "public, max-age=31536000, immutable"

    # API 代理
    @api path /api/*
    handle @api {
        reverse_proxy localhost:8080 {
            lb_policy least_conn
            health_path /healthz
            health_interval 10s
            transport http {
                dial_timeout 3s
                response_header_timeout 30s
                max_idle_conns 200
            }
            flush_interval -1
        }
    }

    # SPA fallback
    handle {
        root * /var/www/dist
        try_files {path} /index.html
        file_server {
            precompressed gzip br
        }
    }

    # 错误页面
    handle_errors {
        root * /var/www/errors
        rewrite * /{http.error.status_code}.html
        file_server
    }
}

小结 / Summary

层级内容
🟢 基础GOMAXPROCS、连接限制、日志性能
🟡 进阶集群证书共享、Prometheus 监控、ELK/Loki 日志、安全加固
🔴 高级插件开发、自定义存储后端、pprof 调试、Nginx 迁移、高流量配置

附录:常用命令速查 / Command Cheat Sheet

# 运行
caddy run                           # 前台运行
caddy start                         # 后台运行
caddy stop                          # 停止后台进程
caddy reload                        # 重载配置
caddy validate --config Caddyfile   # 验证配置
caddy adapt --pretty --config Caddyfile  # Caddyfile → JSON

# 信息
caddy version                       # 版本
caddy list-modules                  # 列出所有模块
caddy list-modules --packages       # 带包名

# 密码
caddy hash-password --plaintext "xxx"  # 生成 bcrypt 哈希

# API
curl http://localhost:2019/config/     # 获取当前配置
curl http://localhost:2019/config/ | jq .  # 格式化输出