Featured image of post Caddy V2 完全指南 🚀

Caddy V2 完全指南 🚀

Caddy V2 完全指南 🚀 🌐 现代化的自动 HTTPS Web 服务器和反向代理 - 简单、安全、高效的Web服务解决方案

Caddy V2 完全指南 🚀

🌐 现代化的自动 HTTPS Web 服务器和反向代理 - 简单、安全、高效的Web服务解决方案


📋 目录


🎯 Caddy V2 简介

Caddy 2 是一款现代化的开源Web服务器,使用Go语言编写,以其简单性和自动HTTPS功能而闻名。

🌟 主要特性

  • 🔒 自动 HTTPS:自动申请和续期 SSL 证书(Let’s Encrypt集成)
  • ⚡ 简单配置:简洁易懂的 Caddyfile 语法,JSON配置选项
  • 🚀 高性能:基于 Go 语言开发,内存占用低,并发能力强
  • 🔧 模块化:支持丰富的扩展功能和中间件
  • 📦 零依赖:单一二进制文件,无需额外运行时
  • 🌐 HTTP/3 支持:原生支持HTTP/3 (QUIC)协议

🆚 版本区别

  • Caddy V1:旧版本,配置语法不同,已停止维护
  • Caddy V2:新版本,完全重写,配置更灵活,本教程适用

🏆 适用场景

  • 个人网站:简单配置,自动HTTPS
  • API 网关:灵活的反向代理和负载均衡
  • 静态网站:高效的文件服务
  • 微服务架构:服务发现和动态配置
  • 开发环境:快速搭建本地HTTPS环境

🐳 Docker 安装

📦 基础安装命令

1
2
3
4
5
6
docker run -d --name=CaddyV2 \
  --net=host \
  -v /path/to/caddy/data:/data \
  -v /path/to/caddy/config:/config \
  -v /path/to/Caddyfile:/etc/caddy/Caddyfile \
  caddy:latest

🎯 推荐安装配置

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
#!/bin/bash
# 🚀 Caddy V2 Docker 安装脚本

CADDY_NAME="CaddyV2"
DATA_DIR="/docker/caddy/data"
CONFIG_DIR="/docker/caddy/config"
CADDYFILE="/docker/caddy/Caddyfile"
WWW_DIR="/www"

# 创建目录
mkdir -p ${DATA_DIR} ${CONFIG_DIR} ${WWW_DIR}
touch ${CADDYFILE}

# 运行容器
docker run -d --name=${CADDY_NAME} \
  --restart=unless-stopped \
  --net=host \
  -v ${DATA_DIR}:/data \
  -v ${CONFIG_DIR}:/config \
  -v ${CADDYFILE}:/etc/caddy/Caddyfile \
  -v ${WWW_DIR}:/www \  # 网站文件目录
  caddy:latest

echo "✅ Caddy V2 安装完成!"
echo "📁 数据目录: ${DATA_DIR}"
echo "📁 配置目录: ${CONFIG_DIR}"
echo "📄 配置文件: ${CADDYFILE}"
echo "🌐 网站目录: ${WWW_DIR}"

🔧 端口映射方式(替代 host 网络)

1
2
3
4
5
6
7
8
docker run -d --name=CaddyV2 \
  -p 80:80 -p 443:443 -p 443:443/udp \  # HTTP/3 需要 UDP 443
  -p 2019:2019 \  # 管理端口(可选)
  -v /docker/caddy/data:/data \
  -v /docker/caddy/config:/config \
  -v /docker/caddy/Caddyfile:/etc/caddy/Caddyfile \
  -v /www:/www \
  caddy:latest

🐳 Docker Compose 部署

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
version: '3.7'

services:
  caddy:
    image: caddy:latest
    container_name: caddy
    restart: unless-stopped
    ports:
      - "80:80"
      - "443:443"
      - "443:443/udp"
    volumes:
      - ./data:/data
      - ./config:/config
      - ./Caddyfile:/etc/caddy/Caddyfile
      - /www:/www
    networks:
      - caddy-network

networks:
  caddy-network:
    driver: bridge

📝 配置文件详解

Caddy 2 支持两种配置格式:Caddyfile(人类可读)和JSON(机器可读)。

🎨 主配置文件结构

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
{
    # 全局配置块
    http_port 80
    https_port 443
    order reverse_proxy before file_server
    auto_https disable_redirects  # 禁用自动HTTPS重定向
    log {
        output file /data/access.log {
            roll_size 100mb
            roll_keep 10
        }
        format json
    }
}

# 导入其他配置文件
import /etc/caddy/conf.d/*.conf

📁 配置文件组织建议

1
2
3
4
5
6
7
/etc/caddy/
├── Caddyfile              # 主配置文件
└── conf.d/               # 子配置目录
    ├── proxy.conf        # 反向代理配置
    ├── static.conf       # 静态文件服务
    ├── api.conf          # API 服务配置
    └── security.conf     # 安全相关配置

🔄 动态配置(API驱动)

Caddy 2 提供了管理API,支持动态配置更新:

1
2
3
4
5
6
7
8
9
# 启用管理API(默认监听2019端口)
{
    admin localhost:2019
}

# 使用API更新配置
curl -X POST "http://localhost:2019/load" \
  -H "Content-Type: text/caddyfile" \
  --data-binary @Caddyfile

🔁 反向代理配置

🎯 基础反向代理

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
# 代理到本地服务
hass.example.com {
    reverse_proxy localhost:8123
}

# 代理到远程服务
api.example.com {
    reverse_proxy https://backend-api:3000
}

# 带路径的反向代理
app.example.com {
    reverse_proxy /api/* localhost:3000
    reverse_proxy /* localhost:8080
}

⚙️ 高级代理配置

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
service.example.com {
    # 负载均衡
    reverse_proxy {
        to server1:8080 server2:8080 server3:8080
        lb_policy round_robin
        
        # 健康检查
        health_uri /health
        health_interval 30s
        health_timeout 5s
        
        # 被动健康检查
        fail_duration 30s
        max_fails 3
    }
    
    # 头部修改
    header_up X-Real-IP {remote_host}
    header_up X-Forwarded-Proto {scheme}
    header_down Strict-Transport-Security "max-age=31536000;"
    
    # 超时设置
    reverse_proxy {
        to backend:8080
        transport http {
            dial_timeout 10s
            tls_timeout 10s
            response_header_timeout 30s
        }
    }
}

🔧 WebSocket 代理

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
ws.example.com {
    reverse_proxy localhost:3000 {
        # WebSocket 支持
        header_up Connection {>Connection}
        header_up Upgrade {>Upgrade}
        
        # WebSocket 特定配置
        transport http {
            keepalive off  # WebSocket 需要关闭 keepalive
        }
    }
}

🔄 服务发现集成

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
service.example.com {
    reverse_proxy {
        # Docker Swarm 服务发现
        to docker-swarm:service-name:8080
        
        # Kubernetes 服务发现
        # to kubernetes:default:service-name:8080
        
        # DNS 服务发现
        # to srv://_http._tcp.service.example.com
    }
}

📁 Web 服务配置

🎯 静态文件服务

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
www.example.com {
    # 文件服务
    root * /www/example
    file_server
    
    # 启用压缩
    encode gzip zstd
    
    # 目录浏览(可选)
    file_server browse {
        hide .gitignore .htaccess
    }
    
    # 自定义错误页面
    handle_errors {
        @404 {
            expression {http.error.status_code} == 404
        }
        rewrite @404 /404.html
        file_server
    }
}

🛡️ 安全增强配置

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
static.example.com {
    root * /www/static
    file_server
    
    # 安全头部
    header {
        X-Content-Type-Options nosniff
        X-Frame-Options DENY
        X-XSS-Protection "1; mode=block"
        Referrer-Policy "no-referrer-when-downgrade"
        Permissions-Policy "geolocation=(), microphone=(), camera=()"
    }
    
    # 缓存控制
    header Cache-Control "public, max-age=3600"
    
    # 防止 MIME 类型混淆攻击
    header Content-Type "{http.response.header.Content-Type}"
    
    # 隐藏服务器信息
    header -Server
}

📄 单页面应用(SPA)支持

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
spa.example.com {
    root * /www/spa
    file_server
    
    # SPA 路由支持
    try_files {path} {path}/ /index.html
    
    # 客户端路由支持
    @clientRoute {
        not file
        path_regexp .*\.(js|css|png|jpg|jpeg|gif|ico|svg|woff|woff2|ttf|eot)$
    }
    rewrite @clientRoute /index.html
}

📊 日志记录

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
# 每个站点的访问日志
blog.example.com {
    root * /www/blog
    file_server
    
    log {
        output file /data/access-blog.log {
            roll_size 100mb
            roll_keep 5
            roll_local_time
        }
        format json {
            time_format "iso8601"
            time_local
        }
    }
}

🔒 HTTPS 配置

🎯 自动 HTTPS(默认)

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
# 自动申请和续期证书
# 默认会重定向HTTP到HTTPS

example.com {
    reverse_proxy localhost:3000
}

# 通配符证书
*.example.com {
    tls {
        dns cloudflare {env.CLOUDFLARE_API_TOKEN}
    }
    
    reverse_proxy localhost:3000
}

📝 手动指定证书

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
https://example.com:444 {
    tls /path/to/cert.pem /path/to/key.pem
    
    reverse_proxy localhost:3000
}

# 使用ACME挑战
example.com {
    tls {
        ca https://acme-staging-v02.api.letsencrypt.org/directory
        dns cloudflare {env.CLOUDFLARE_API_TOKEN}
    }
    
    reverse_proxy localhost:3000
}

🌐 HTTP 重定向到 HTTPS

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
# 显式重定向
http://example.com {
    redir https://{host}{uri} permanent
}

https://example.com {
    reverse_proxy localhost:3000
}

# 或者使用自动HTTPS重定向(默认行为)
example.com {
    reverse_proxy localhost:3000
}

🚫 纯 HTTP 服务

1
2
3
4
5
6
7
http://example.com:8080 {
    root * /www/http
    file_server
    
    # 禁用TLS
    tls off
}

🔐 客户端证书认证

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
secure.example.com {
    tls /path/to/cert.pem /path/to/key.pem {
        client_auth {
            mode require_and_verify
            trusted_ca_cert_file /path/to/client-ca.crt
        }
    }
    
    reverse_proxy localhost:3000
}

⚙️ 高级配置

🔐 身份验证

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
admin.example.com {
    # Basic 认证
    basicauth /admin/* {
        admin $2y$10$xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
        user2 $2y$10$yyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyy
    }
    
    # JWT 认证
    jwt {
        primary yes
        allow sub user1 user2
        secret {env.JWT_SECRET}
    }
    
    reverse_proxy localhost:3000
}

📊 高级日志配置

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
{
    log {
        # 访问日志
        output file /data/access.log {
            roll_size 1gb
            roll_keep 10
            roll_local_time
            roll_uncompressed
        }
        format json {
            time_format "iso8601"
            time_local
        }
        
        # 错误日志
        output file /data/error.log {
            roll_size 50mb
            roll_keep 5
            roll_local_time
        }
        level ERROR
    }
}

⚡ 性能优化

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
{
    # 缓冲区大小
    buffers {
        read 4096
        write 4096
    }
    
    # 连接超时
    timeouts {
        read 30s
        write 30s
        idle 2m
        graceful_shutdown 15s
    }
    
    # 压缩设置
    encode {
        gzip {
            level 6
            min_length 256
        }
        zstd
    }
    
    # 静态资源缓存
    file_server {
        cache {
            max_age 1h
        }
    }
}

🔄 重写和重定向规则

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
example.com {
    # URL 重写
    rewrite /old/path /new/path
    
    # 正则重写
    rewrite /user/(\w+) /profile?name={1}
    
    # 条件重定向
    @mobile {
        header User-Agent *mobile*
    }
    redir @mobile /mobile{uri}
    
    # 永久重定向
    redir https://new.example.com{uri} permanent
    
    # 基于查询参数的重定向
    @withToken {
        query token=*
    }
    redir @withToken /auth{uri}
}

🧩 中间件和插件

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
example.com {
    # 启用CORS
    header Access-Control-Allow-Origin *
    header Access-Control-Allow-Methods "GET, POST, OPTIONS"
    header Access-Control-Allow-Headers "Content-Type, Authorization"
    
    # 速率限制
    rate_limit {
        zone rate_limit_zone 10 1s
        key {remote_host}
    }
    
    # IP白名单
    @whitelist {
        remote_ip 192.168.1.0/24 10.0.0.0/8
    }
    respond @whitelist 403
    
    reverse_proxy localhost:3000
}

🔧 故障排除

🐛 常见问题解决

1. 端口被占用

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
# 检查端口占用
sudo lsof -i :80
sudo lsof -i :443

# 停止占用进程或修改 Caddy 端口
{
    http_port 8080
    https_port 8443
}

# 或者杀死占用进程
sudo kill -9 $(sudo lsof -t -i:80)

2. 证书申请失败

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
# 检查 DNS 解析
dig example.com
nslookup example.com

# 检查防火墙
sudo ufw status
sudo firewall-cmd --list-all

# 检查ACME挑战目录权限
ls -la /www/.well-known/acme-challenge/

# 使用暂存环境测试
{
    acme_ca https://acme-staging-v02.api.letsencrypt.org/directory
}

3. 权限问题

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
# 检查文件权限
ls -la /path/to/www

# 修复权限
sudo chown -R www-data:www-data /path/to/www
sudo chmod -R 755 /path/to/www

# 检查SELinux/AppArmor
sudo sestatus
sudo aa-status

📝 日志查看和调试

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
# 查看容器日志
docker logs CaddyV2
docker logs -f CaddyV2  # 实时日志

# 查看访问日志
tail -f /docker/caddy/data/access.log

# 查看错误日志
docker exec CaddyV2 cat /data/caddy.log

# 启用调试模式
{
    debug
}

# 或者使用环境变量
docker run -e CADDY_DEBUG=true ... caddy:latest

🔍 配置验证和测试

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
# 验证配置文件语法
docker exec CaddyV2 caddy validate --config /etc/caddy/Caddyfile

# 重新加载配置
docker exec CaddyV2 caddy reload --config /etc/caddy/Caddyfile

# 测试配置
docker exec CaddyV2 caddy adapt --config /etc/caddy/Caddyfile

# 检查当前运行配置
curl http://localhost:2019/config/ | jq .

🚀 性能监控和优化

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
# 查看容器资源使用
docker stats CaddyV2

# 查看连接数
docker exec CaddyV2 caddy metrics

# 实时监控
watch -n 1 'docker stats CaddyV2 --no-stream'

# 压力测试
ab -n 1000 -c 100 https://example.com/

🔄 维护和更新

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
# 更新 Caddy
docker pull caddy:latest
docker stop CaddyV2
docker rm CaddyV2
# 重新运行安装命令

# 备份配置
tar -czvf caddy-backup-$(date +%Y%m%d).tar.gz /docker/caddy/

# 恢复配置
tar -xzvf caddy-backup-20231201.tar.gz -C /

# 清理旧证书和数据
docker exec CaddyV2 caddy cleanup

🎯 提示:Caddy V2 的配置非常灵活,建议从简单配置开始,逐步添加复杂功能。定期备份配置文件和证书数据。

📚 推荐资源

🔧 维护命令

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
# 查看Caddy版本
docker exec CaddyV2 caddy version

# 列出已安装插件
docker exec CaddyV2 caddy list-modules

# 检查证书状态
docker exec CaddyV2 caddy validate --config /etc/caddy/Caddyfile

# 强制更新证书
docker exec CaddyV2 caddy reload --force

💡 最佳实践

  1. 使用Docker Compose管理Caddy容器
  2. 将配置和数据目录映射到宿主机
  3. 定期备份证书和配置
  4. 使用环境变量管理敏感信息
  5. 启用适当的日志记录和监控
  6. 定期更新Caddy到最新版本

🌐 社区支持

希望本指南能帮助您顺利使用Caddy V2搭建和管理Web服务!🚀

最后更新于 2025-09-28