Skip to content

Instantly share code, notes, and snippets.

@Starrah
Last active March 6, 2025 06:36
Caddyfile实用技巧
各种Caddyfile实用技巧
目录:
- basic_auth
- cert_by_dns
- cors常用宏
- file_server
- hsts
- http和https共用一个端口
- redir
- reverse_proxy HTTPS
- 多路复用
个人常用的xcaddy编译命令:
xcaddy build --with github.com/caddy-dns/dnspod --with github.com/mholt/caddy-l4
# 生成密码的命令:caddy hash-password
# 直接替换掉下面具体配置中的xxxxxxxx就可以
(PASS_USER) { # 使用该宏,upstream可以从X-Caddy-Username头中拿到用户名
header_up X-Caddy-Username {http.auth.user.id}
}
example1.com {
basic_auth { # 注意!caddy v2.8.0以前,这个命令名字叫basicauth
Bob xxxxxxxx
}
reverse_proxy 127.0.0.1:9000 {
import PASS_USER # 可选,如果后端不需要用户名就不用加这个
}
}
(CERT_BY_DNS) {
tls {
dns dnspod xxxxxx,yyyyyyyyyyyyyyyyyy
propagation_delay 20s # 否则,由于发送API和实际DNS缓存更新之间的延迟,证书极容易申请失败
propagation_timeout 10m
}
}
example.com {
import CERT_BY_DNS
# ......
}
(CORS) { # 基本的CORS头(不含Allow-Credentials)
header Access-Control-Allow-Origin {header.Origin}
header Access-Control-Allow-Method "GET, POST, PUT, DELETE"
header Access-Control-Max-Age 600
header +Vary Origin
@METHOD_IS_OPTIONS method OPTIONS
respond @METHOD_IS_OPTIONS 204
}
(CORS_Cred) { # 仅用于和(CORS)补充使用,单用没有意义
header Access-Control-Allow-Credentials true
header Access-Control-Allow-Headers "*, Authorization, Content-Type"
}
# 因为caddy不允许matcher在全局scope中定义,所以只能是定义成一个snippet,再在需要用到的地方import进来
(ORIGIN) { # 定义一个matcher,匹配Origin来自特定网站的情况。
# 第一个参数:matcher的名字的后缀,可任意传。例:传入abc,则定义出来的matcher名为@ORIGIN_abc
# 第二个参数:域名。注意!域名中的点"."要转义为"\.",否则会存在安全问题!
@ORIGIN_{args[0]} header_regexp Origin "^https?:\/\/(.+\.)*{args[1]}(:\d+)?$"
}
example.com { # 对所有Origin都允许CORS
import CORS
# route @xxx { # 可以只针对特定的matcher,额外发送cred头
# import CORS_Cred
# }
# ......
}
example2.com { # 只对xxx.com的子域名允许CORS
import ORIGIN 1 xxx\.com # 引入名为@ORIGIN_1的matcher。注意第二个参数xxx.com中,点需要转义为\.
route @ORIGIN_1 { # 只有对Origin是xxx.com的子域名,才发送CORS头
import CORS # PS: 疑似只有较高版本才允许route内部嵌套新的matcher定义,所以不排除较老版本这么写会报错
# import CORS_Cred # 可选
}
# ......
}
# 注意,systemd的caddy是Private-tmp的,与主系统不共享tmp!
# 可以浏览文件
example.com {
root * /var/www/qwq # 必须加星号,否则会混淆为matcher
file_server browse
}
# 找不到就落到反向代理(适合前后端的情况)
example.com {
root * /var/www/qwq # 必须加星号,否则会混淆为matcher
route { # 必须使用route控制顺序,否则默认file_server优先级是最低的
file_server pass_thru
reverse_proxy localhost:6789
}
}
(HSTS) {
header Strict-Transport-Security max-age=31536000;
}
example.com {
import HSTS
}
# 注意!以下代码只能放在文件的最开头。
# 因为layer4部分是app配置,根据规则,app配置之前不能有snippets以外的东西。
# 依赖模块github.com/mholt/caddy-l4
(SHARE_PORT) { # 固定不动的部分
@SHARE_PORT_p_{args[0]} http host {args[0]}
route @SHARE_PORT_p_{args[0]} {
proxy localhost:10080
}
@SHARE_PORT_s_{args[0]} tls sni {args[0]}
route @SHARE_PORT_s_{args[0]} {
proxy localhost:443
}
}
{
layer4 { # 具体需要修改的部分
[::]:20080 { # 这里配置需要共用的端口号
import SHARE_PORT example.com # 这里配置需要处理的域名
import SHARE_PORT example2.com
}
}
}
:10080 { # 固定不动的部分
redir https://{hostport}{uri} 308
}
example.com { # 实际server的配置。注意这里不能写出example.com:20080
reverse_proxy http://localhost:9100
}
example2.com { # 实际server的配置。注意这里不能写出example2.com:20080
reverse_proxy http://localhost:9200
}
# 基于以上配置,example.com和example2.com,既可以通过标准不带端口号的http和https(80/443)访问,也可以通过20080端口、同时通过http和https访问。
example.com, http://example.com {
redir https://example2.com{uri} permanent
}
(PROXY_DOMAIN) {
header_up Host {upstream_hostport}
header_up X-Forwarded-Host {host}
}
example.com {
import PROXY_DOMAIN # 否则,被代理的站点example2.com看到的Host还是,example.com无法正确识别Host也就无法正确给出证书
reverse_proxy https://example2.com:6789
}
# 一个域名,多个上游
example.com {
handle_path /aaa/* {
reverse_proxy 127.0.0.1:9100
}
handle_path /bbb/* {
reverse_proxy 127.0.0.1:9200
}
}
# 多个域名,一个上游的不同子目录
example1.com {
rewrite * /aaa{uri}
reverse_proxy 127.0.0.1:9000
}
example2.com {
rewrite * /bbb{uri}
reverse_proxy 127.0.0.1:9000
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment