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
|
💡 最佳实践:
- 使用Docker Compose管理Caddy容器
- 将配置和数据目录映射到宿主机
- 定期备份证书和配置
- 使用环境变量管理敏感信息
- 启用适当的日志记录和监控
- 定期更新Caddy到最新版本
🌐 社区支持:
希望本指南能帮助您顺利使用Caddy V2搭建和管理Web服务!🚀