API 配置 #

概述 #

Caddy 提供了强大的管理 API,允许动态修改配置、管理证书、查看状态等,无需重启服务。

text
┌─────────────────────────────────────────────────────────────┐
│                    Caddy API 架构                            │
├─────────────────────────────────────────────────────────────┤
│                                                             │
│    ┌─────────────┐                                          │
│    │   客户端    │                                          │
│    └──────┬──────┘                                          │
│           │ HTTP 请求                                       │
│           ▼                                                 │
│    ┌─────────────┐                                          │
│    │  管理 API   │  localhost:2019                          │
│    │  端口 2019  │                                          │
│    └──────┬──────┘                                          │
│           │                                                 │
│           ▼                                                 │
│    ┌─────────────┐                                          │
│    │  配置存储    │                                          │
│    └─────────────┘                                          │
│                                                             │
└─────────────────────────────────────────────────────────────┘

API 端点 #

基本端点 #

端点 方法 说明
/config/ GET 获取完整配置
/config/ POST 设置完整配置
/load POST 加载配置
/adapt POST 转换配置格式
/stop POST 停止服务器
/certificates GET 获取证书列表
/pki/ca GET 获取 CA 信息
/reverse_proxy/upstreams GET 获取代理上游状态

配置管理 #

获取当前配置 #

bash
# 获取完整配置
curl localhost:2019/config/ | jq

# 获取特定部分
curl localhost:2019/config/apps/http | jq

# 获取服务器配置
curl localhost:2019/config/apps/http/servers | jq

加载配置 #

bash
# 加载 JSON 配置
curl -X POST \
    -H "Content-Type: application/json" \
    -d @caddy.json \
    localhost:2019/load

# 加载 Caddyfile
curl -X POST \
    -H "Content-Type: application/json" \
    --data-binary '{"admin":"off"}' \
    localhost:2019/load

更新部分配置 #

bash
# 使用 PATCH 更新部分配置
curl -X PATCH \
    -H "Content-Type: application/json" \
    -d '{"email": "new@example.com"}' \
    localhost:2019/config/

# 更新特定路径
curl -X PATCH \
    -H "Content-Type: application/json" \
    -d '["example.com"]' \
    localhost:2019/config/apps/http/servers/srv0/listen

删除配置 #

bash
# 删除特定配置
curl -X DELETE localhost:2019/config/apps/http/servers/srv0/routes/0

动态添加站点 #

添加新站点 #

bash
# 添加新站点配置
curl -X POST \
    -H "Content-Type: application/json" \
    -d '{
        "match": [{
            "host": ["new.example.com"]
        }],
        "handle": [{
            "handler": "subroute",
            "routes": [{
                "handle": [{
                    "handler": "reverse_proxy",
                    "upstreams": [{
                        "dial": "localhost:4000"
                    }]
                }]
            }]
        }],
        "terminal": true
    }' \
    localhost:2019/config/apps/http/servers/srv0/routes

添加静态站点 #

bash
curl -X POST \
    -H "Content-Type: application/json" \
    -d '{
        "match": [{
            "host": ["static.example.com"]
        }],
        "handle": [{
            "handler": "subroute",
            "routes": [{
                "handle": [{
                    "handler": "file_server",
                    "root": "/var/www/static"
                }]
            }]
        }],
        "terminal": true
    }' \
    localhost:2019/config/apps/http/servers/srv0/routes

反向代理管理 #

添加后端服务器 #

bash
# 添加新的后端
curl -X POST \
    -H "Content-Type: application/json" \
    -d '{"dial": "server4:3000"}' \
    localhost:2019/config/apps/http/servers/srv0/routes/0/handle/0/routes/0/handle/0/upstreams

查看上游状态 #

bash
# 获取所有上游状态
curl localhost:2019/reverse_proxy/upstreams | jq

# 输出示例
{
    "upstreams": [
        {
            "address": "localhost:3000",
            "healthy": true,
            "requests": 1234,
            "fails": 2
        },
        {
            "address": "localhost:3001",
            "healthy": true,
            "requests": 1180,
            "fails": 1
        }
    ]
}

移除后端服务器 #

bash
# 移除第一个后端
curl -X DELETE \
    localhost:2019/config/apps/http/servers/srv0/routes/0/handle/0/routes/0/handle/0/upstreams/0

证书管理 #

查看证书 #

bash
# 获取所有证书
curl localhost:2019/certificates | jq

# 输出示例
{
    "certificates": [
        {
            "domains": ["example.com", "www.example.com"],
            "issuer": "Let's Encrypt",
            "not_before": "2024-01-01T00:00:00Z",
            "not_after": "2024-04-01T00:00:00Z"
        }
    ]
}

手动获取证书 #

bash
# 通过配置触发证书获取
curl -X POST \
    -H "Content-Type: application/json" \
    -d '{
        "email": "admin@example.com",
        "domains": ["new.example.com"]
    }' \
    localhost:2019/certificates

配置导出 #

导出为 JSON #

bash
# 导出完整配置
curl localhost:2019/config/ > caddy-backup.json

# 导出特定部分
curl localhost:2019/config/apps/http > http-config.json

导出为 Caddyfile #

bash
# Caddyfile 转 JSON
caddy adapt --config Caddyfile --pretty > caddy.json

# JSON 转 Caddyfile(需要手动编写)

API 配置 #

启用/禁用 API #

caddyfile
{
    # 启用 API(默认)
    admin :2019
    
    # 禁用 API
    # admin off
    
    # 只监听本地
    admin localhost:2019
    
    # 监听所有接口(不推荐)
    # admin 0.0.0.0:2019
}

API 认证 #

caddyfile
{
    admin {
        # 使用基础认证保护 API
        # 需要配置中间件
    }
}

使用防火墙保护 API #

bash
# 只允许本地访问
sudo ufw allow from 127.0.0.1 to any port 2019

# 或使用 iptables
sudo iptables -A INPUT -p tcp --dport 2019 -s 127.0.0.1 -j ACCEPT
sudo iptables -A INPUT -p tcp --dport 2019 -j DROP

实用 API 示例 #

批量添加站点 #

bash
#!/bin/bash
# add-sites.sh

sites=(
    "site1.example.com:3001"
    "site2.example.com:3002"
    "site3.example.com:3003"
)

for site in "${sites[@]}"; do
    IFS=':' read -r domain port <<< "$site"
    
    curl -X POST \
        -H "Content-Type: application/json" \
        -d "{
            \"match\": [{\"host\": [\"$domain\"]}],
            \"handle\": [{
                \"handler\": \"subroute\",
                \"routes\": [{
                    \"handle\": [{
                        \"handler\": \"reverse_proxy\",
                        \"upstreams\": [{\"dial\": \"localhost:$port\"}]
                    }]
                }]
            }],
            \"terminal\": true
        }" \
        localhost:2019/config/apps/http/servers/srv0/routes
    
    echo "Added $domain"
done

蓝绿部署切换 #

bash
#!/bin/bash
# blue-green-switch.sh

MODE=$1  # blue or green

if [ "$MODE" == "blue" ]; then
    WEIGHTS='[{"dial": "blue-1:3000", "weight": 10}, {"dial": "blue-2:3000", "weight": 10}, {"dial": "green-1:3000", "weight": 0}, {"dial": "green-2:3000", "weight": 0}]'
elif [ "$MODE" == "green" ]; then
    WEIGHTS='[{"dial": "blue-1:3000", "weight": 0}, {"dial": "blue-2:3000", "weight": 0}, {"dial": "green-1:3000", "weight": 10}, {"dial": "green-2:3000", "weight": 10}]'
else
    echo "Usage: $0 blue|green"
    exit 1
fi

curl -X PATCH \
    -H "Content-Type: application/json" \
    -d "$WEIGHTS" \
    localhost:2019/config/apps/http/servers/srv0/routes/0/handle/0/routes/0/handle/0/upstreams

echo "Switched to $MODE environment"

金丝雀发布 #

bash
#!/bin/bash
# canary-release.sh

CANARY_WEIGHT=$1
STABLE_WEIGHT=$((100 - CANARY_WEIGHT))

curl -X PATCH \
    -H "Content-Type: application/json" \
    -d "[
        {\"dial\": \"stable-1:3000\", \"weight\": $STABLE_WEIGHT},
        {\"dial\": \"stable-2:3000\", \"weight\": $STABLE_WEIGHT},
        {\"dial\": \"canary-1:3000\", \"weight\": $CANARY_WEIGHT},
        {\"dial\": \"canary-2:3000\", \"weight\": $CANARY_WEIGHT}
    ]" \
    localhost:2019/config/apps/http/servers/srv0/routes/0/handle/0/routes/0/handle/0/upstreams

echo "Canary weight set to $CANARY_WEIGHT%"

健康检查脚本 #

bash
#!/bin/bash
# health-check.sh

# 检查 API 是否响应
if curl -s localhost:2019/config/ > /dev/null; then
    echo "API is healthy"
else
    echo "API is not responding"
    exit 1
fi

# 检查后端健康状态
UNHEALTHY=$(curl -s localhost:2019/reverse_proxy/upstreams | jq '[.upstreams[] | select(.healthy == false)] | length')

if [ "$UNHEALTHY" -gt 0 ]; then
    echo "Warning: $UNHEALTHY unhealthy upstream(s)"
else
    echo "All upstreams are healthy"
fi

配置持久化 #

自动保存配置 #

caddyfile
{
    # 配置持久化
    persist_config
}

手动保存配置 #

bash
# 导出当前配置
curl localhost:2019/config/ > /etc/caddy/caddy.json

# 使用 JSON 配置启动
caddy run --config /etc/caddy/caddy.json

API 安全 #

限制 API 访问 #

caddyfile
{
    # 只监听本地
    admin localhost:2019
    
    # 或使用 Unix Socket
    admin {
        listen unix//var/run/caddy.sock
    }
}

使用 TLS 保护 API #

caddyfile
{
    admin {
        # 使用 TLS
        listen :2019
        tls {
            certificate /etc/ssl/caddy-api.crt
            key /etc/ssl/caddy-api.key
        }
    }
}

API 访问日志 #

caddyfile
{
    admin {
        # 记录 API 访问
        log {
            output file /var/log/caddy/admin.log
        }
    }
}

完整示例 #

动态配置管理系统 #

bash
#!/bin/bash
# caddy-manager.sh

API="localhost:2019"

# 添加站点
add_site() {
    local domain=$1
    local backend=$2
    
    curl -s -X POST \
        -H "Content-Type: application/json" \
        -d "{
            \"match\": [{\"host\": [\"$domain\"]}],
            \"handle\": [{
                \"handler\": \"subroute\",
                \"routes\": [{
                    \"handle\": [{
                        \"handler\": \"reverse_proxy\",
                        \"upstreams\": [{\"dial\": \"$backend\"}]
                    }]
                }]
            }],
            \"terminal\": true
        }" \
        "$API/config/apps/http/servers/srv0/routes" > /dev/null
    
    echo "Added site: $domain -> $backend"
}

# 删除站点
remove_site() {
    local index=$1
    
    curl -s -X DELETE \
        "$API/config/apps/http/servers/srv0/routes/$index"
    
    echo "Removed site at index $index"
}

# 列出站点
list_sites() {
    curl -s "$API/config/apps/http/servers/srv0/routes" | \
        jq -r '.[] | select(.match[0].host) | .match[0].host[0]'
}

# 查看状态
status() {
    echo "=== Upstreams ==="
    curl -s "$API/reverse_proxy/upstreams" | jq
    
    echo -e "\n=== Certificates ==="
    curl -s "$API/certificates" | jq
    
    echo -e "\n=== Config ==="
    curl -s "$API/config/apps/http/servers/srv0/routes" | jq 'length'
}

case "$1" in
    add)
        add_site "$2" "$3"
        ;;
    remove)
        remove_site "$2"
        ;;
    list)
        list_sites
        ;;
    status)
        status
        ;;
    *)
        echo "Usage: $0 {add|remove|list|status}"
        ;;
esac

下一步 #

现在你已经掌握了 API 配置,接下来学习 限流限速 了解如何保护你的服务!

最后更新:2026-03-28