Caddy 配置指南

Caddyfile 结构图解

Caddyfile 由全局选项块、可复用片段和站点块组成,通过匹配器与指令处理请求。

{
    email you@yours.com
    acme_ca https://acme-staging-v02.api.letsencrypt.org/directory
}

(snippet) {
    # this is a reusable snippet
}

example.com {
    @post {
        method POST
    }

    reverse_proxy @post localhost:9001 localhost:9002 {
        lb_policy first
    }
    file_server /static
    import snippet
}

www.example.com {
    redir https://example.com{uri}
    import snippet
}
Global options block
Snippet
Site block
Matcher definition
Option name
Option value
Comment
Site address
Directive
Matcher token
Argument
Subdirective

同时监听 80 和 443

Caddy 默认在启用自动 HTTPS 时就会监听 80 和 443。80 用于 ACME 挑战并自动重定向到 HTTPS。

# 默认行为:只需写域名,Caddy 自动监听 80 和 443
example.com {
    root * /var/www/html
    file_server
}

手动显式配置两个端口:

# 80 端口:强制跳转 HTTPS
:80 {
    redir https://{host}{uri} permanent
}

# 443 端口:正常提供服务,自动申请证书
example.com {
    root * /var/www/html
    file_server
}
端口被占用? 可在全局块中修改默认端口: http_port 8080https_port 8443

HTTP Basic Authentication

先用 caddy hash-password 生成 bcrypt 哈希,再在站点块中配置。

# 生成密码哈希
$ caddy hash-password --plaintext '你的密码'
$2a$14$xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
example.com {
    basic_auth {
        admin $2a$14$xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
        guest $2a$14$yyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyy
    }

    root * /var/www/html
    file_server
}
版本差异:Caddy v2.8+ 使用 basic_auth,v2.0 ~ v2.7 使用 basicauth(无下划线)。

指定路径反向代理 + Basic Auth

handle 块把认证和反代限定在特定路径下,其他路径不受影响。

example.com {
    # 只处理 /api/* 路径
    handle /api/* {
        basic_auth {
            admin $2a$14$xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
        }
        reverse_proxy localhost:9000
    }

    # 其他路径走静态文件
    handle {
        root * /var/www/html
        file_server
    }
}

如果上游不希望看到 /api 前缀,改用 handle_path

handle_path /api/* {
    basic_auth { admin $2a$14$xxxxxxxx... }
    reverse_proxy localhost:9000
}
/api/users 会被代理到上游的 /users,前缀被自动剥离。

多个路径共用同一反代配置

用命名匹配器一次性匹配多个路径,避免重复写多个 handle 块。

example.com {
    # 一个匹配器同时匹配多个路径
    @backend path /api/* /v1/* /v2/*

    handle @backend {
        basic_auth {
            admin $2a$14$xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
        }
        reverse_proxy localhost:9000
    }

    # 兜底:其他路径
    handle {
        root * /var/www/html
        file_server
    }
}

如果多个路径需要去前缀,且前缀不同,可以用 snippet 复用公共配置:

(protected_proxy) {
    basic_auth {
        admin $2a$14$xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
    }
    reverse_proxy localhost:9000
}

example.com {
    handle_path /api/* { import protected_proxy }
    handle_path /v1/*  { import protected_proxy }

    handle {
        file_server
    }
}

无公网 IP:DNS-01 挑战

没有公网 IP 时,HTTP-01 挑战无法工作,改用 DNS-01 挑战即可正常签发证书。

# 1. 构建带 DNS 插件的 Caddy(以 Cloudflare 为例)
$ xcaddy build --with github.com/caddy-dns/cloudflare
{
    email your-email@example.com
    acme_dns cloudflare {env.CLOUDFLARE_API_TOKEN}
}

example.com {
    root * /var/www/html
    file_server
}

也可以只在单个站点启用:

example.com {
    tls {
        dns cloudflare {env.CLOUDFLARE_API_TOKEN}
    }
    reverse_proxy localhost:8080
}
API Token 权限:Cloudflare 需要 Zone / Zone / ReadZone / DNS / Edit。其他 DNS 提供商见 github.com/orgs/caddy-dns/repositories

常用命令速查

修改配置后先验证语法,再平滑重载服务。

命令 说明
caddy validate --config /etc/caddy/Caddyfile 校验配置文件语法
caddy adapt --config ./Caddyfile --pretty 转换为 JSON 配置查看最终效果
caddy fmt --overwrite /etc/caddy/Caddyfile 格式化 Caddyfile
caddy hash-password --plaintext '密码' 生成 Basic Auth 密码哈希
caddy run 前台运行(调试用)
caddy start 后台运行
sudo systemctl reload caddy 平滑重载(不中断连接)
sudo systemctl status caddy 查看运行状态
sudo ss -tlnp | grep caddy 查看监听端口
推荐工作流: caddy validatesystemctl reload caddysystemctl status caddy