跳转至

Caddy 反向代理

Caddy 是一个现代的、易于使用的反向代理,具有自动 HTTPS 功能。

为什么选择 Caddy?

  • 自动 HTTPS: 开箱即用的 Let's Encrypt 集成
  • 简单配置: 人类可读的 Caddyfile
  • HTTP/2 & HTTP/3: 现代协议支持
  • 动态重载: 无需重启即可更改配置

基本配置

创建 /etc/caddy/Caddyfile

{
    auto_https off  # 如果在另一个代理后面则禁用
    admin off       # 禁用管理 API(可选)
}

api.yourstore.com {
    # 反向代理到 R Commerce
    reverse_proxy localhost:8080

    # 文件上传大小
    request_body {
        max_size 50MB
    }

    # 安全头
    header {
        X-Frame-Options "SAMEORIGIN"
        X-Content-Type-Options "nosniff"
        X-XSS-Protection "1; mode=block"
        Referrer-Policy "strict-origin-when-cross-origin"
        -Server  # 移除服务器头
    }

    # 日志
    log {
        output file /var/log/caddy/access.log
        format json
    }

    # 压缩响应
    encode gzip zstd
}

自动 HTTPS

Caddy 自动获取和续期证书:

api.yourstore.com {
    reverse_proxy localhost:8080

    # TLS 是自动的,但您可以自定义:
    tls {
        protocols tls1.2 tls1.3
        ciphers TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256 TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256
    }
}

负载均衡

多个 R Commerce 实例:

api.yourstore.com {
    reverse_proxy {
        to 10.0.1.10:8080 10.0.1.11:8080 10.0.1.12:8080

        # 负载均衡策略
        lb_policy least_conn

        # 健康检查
        health_uri /health
        health_interval 10s
        health_timeout 5s
    }
}

负载均衡策略

策略 说明
random 随机选择
random_choose 2 随机选择 2 个
least_conn 最少活跃连接
round_robin 均匀分布
first 第一个可用
ip_hash 基于客户端 IP
uri_hash 基于请求 URI

速率限制

{
    order rate_limit before basicauth
}

api.yourstore.com {
    # 速率限制:每个 IP 每秒 10 个请求
    rate_limit {
        zone static_example {
            key static
            events 10
            window 1s
        }
    }

    reverse_proxy localhost:8080
}

或使用 http.rate_limit 模块:

api.yourstore.com {
    rate_limit {
        zone ip_limit {
            key {remote_host}
            events 100
            window 1m
        }
    }

    reverse_proxy localhost:8080
}

缓存

{
    order cache before rewrite
}

api.yourstore.com {
    # 缓存 API 响应
    cache {
        ttl 5m
        stale 1h
    }

    reverse_proxy localhost:8080
}

WebSocket 支持

Caddy 自动处理 WebSocket:

api.yourstore.com {
    # WebSocket 连接自动升级
    reverse_proxy localhost:8080

    # 增加长连接的超时
    timeouts {
        read_body 0
        read_header 30s
        write 0
        idle 5m
    }
}

请求/响应操作

api.yourstore.com {
    # 添加自定义头到上游
    reverse_proxy localhost:8080 {
        header_up X-Real-IP {remote_host}
        header_up X-Forwarded-Proto {scheme}
    }

    # 修改响应头
    header_down Server "R Commerce"

    # 移除敏感头
    header_down -X-Powered-By
}

多站点

# API 服务器
api.yourstore.com {
    reverse_proxy localhost:8080
}

# 管理面板
admin.yourstore.com {
    reverse_proxy localhost:8081

    # IP 限制
    @not_allowed {
        not remote_ip 10.0.0.0/8 172.16.0.0/12
    }
    respond @not_allowed "Forbidden" 403
}

# 静态文件
static.yourstore.com {
    root /var/www/static
    file_server
    encode gzip
}

日志

api.yourstore.com {
    reverse_proxy localhost:8080

    log {
        output file /var/log/caddy/access.log {
            roll_size 100MB
            roll_keep 10
            roll_keep_days 30
        }
        format json {
            time_format iso8601
        }
    }
}

Docker Compose

version: '3.8'

services:
  caddy:
    image: caddy:2-alpine
    ports:
      - "80:80"
      - "443:443"
    volumes:
      - ./Caddyfile:/etc/caddy/Caddyfile
      - caddy_data:/data
      - caddy_config:/config
    depends_on:
      - rcommerce

  rcommerce:
    image: rcommerce:latest
    environment:
      - RCOMMERCE_CONFIG=/etc/rcommerce/config.toml
    volumes:
      - ./config.toml:/etc/rcommerce/config.toml

管理命令

# 验证配置
caddy validate --config /etc/caddy/Caddyfile

# 重载配置
caddy reload --config /etc/caddy/Caddyfile

# 启动 Caddy
caddy run --config /etc/caddy/Caddyfile

# 作为服务运行
systemctl start caddy
systemctl enable caddy

故障排除

问题 解决方案
证书错误 检查 DNS 和防火墙以进行 ACME 挑战
502 错误 验证 R Commerce 是否正在运行
配置无法加载 运行 caddy validate 检查语法
高内存 调整 GOGC 环境变量

从 Nginx 迁移

Nginx Caddy
proxy_pass reverse_proxy
ssl_certificate 自动(或 tls
gzip on encode gzip
client_max_body_size request_body max_size
add_header header
access_log log