Caddy 是一个 Web 服务器:一个 exe,配五行文本就能把目录挂成网站,还能当反向代理、自动申请证书。它把 Nginx 那些需要查文档才敢改的配置,压成了一份能读懂的 Caddyfile。

它解决的问题是「起个服务太麻烦」。装 Nginx 要改 conf、加站点,再重启看日志,Caddy 直接一条命令读配置就跑。

这次从解压到出页面全跑了一遍:版本命令 0.39 秒,配置转换 0.24 秒,服务起来 0.61 秒,50 次请求的中间延迟 0.9 毫秒。

一个 exe 当 Web 服务器

zip 18479498 字节,解开三个文件:caddy.exe、README.md 和一份 LICENSE。解压 0.33 秒,没有安装向导,不写注册表。

它是 Go 编译的单文件,不依赖 .NET 也不依赖 node。要开机自启,得自己做一个计划任务或者服务,它不自带这个功能。

文件字节
zip 包18479498
caddy.exe53159936
README.md12661
LICENSE11358

版本命令 0.39 秒

跑 caddy version 输出一行版本号加一串哈希:v2.11.7 h1:yj0Y4fYZGPkSvib…。后面那串是构建哈希,用来确认二进制没被人改过。

0.39 秒里大部分是进程启动。Go 的单文件程序都这样,冷启动几十毫秒到几百毫秒,跟文件大小有关。

五行配置换 34 行 JSON

Caddyfile 的语法是「地址 + 花括号 + 指令」。这份配置一共十行,去掉空行和括号,实际指令 4 条。

{
	admin 127.0.0.1:2019
	http_port 8082
}
:8082 {
	root * D:/wb_cache/batch3/www
	file_server browse
}

caddy adapt 把它翻译成 Caddy 真正执行的 JSON:492 字节、34 行。这个命令的价值在于能验证配置有没有写错,不启动服务也能查。

命令耗时输出
caddy version0.39 秒v2.11.7
caddy adapt0.24 秒492 字节 / 34 行 JSON
caddy run 起来0.61 秒8082 端口可访问
目录页加载0.05 秒0.05 秒到可交互

http_port 这一行是为了避开 80

默认它会去抢 80 和 443。开发和测试机上这两个端口经常被占,所以在全局块里写 http_port 8082,把明文端口换掉。

不换也能跑,但一旦 80 被占,启动直接失败退出。日志里是一行 bind 错误,不会告诉你该改哪。

目录浏览页是自带的

file_server browse 这个指令打开目录列表。访问一个没有 index.html 的目录时,它会生成一个带搜索框的页面。

页面上有路径面包屑、文件数统计,还有 Name 和 Size 加上 Modified 三列,还能在 List 和 Grid 两种视图之间切。「3 files 14 KiB total」这行是它自己算的。

Caddy file_server browse 生成的目录页:路径面包屑、3 files 14 KiB total、Name 与 Size 加 Modified 三列,底部 Served with caddy

文件服务只要两行

root * 路径 指定根目录,file_server browse 打开列表。这两行合起来就是一个静态站点。

不带 browse 参数时,访问目录会返回 404,只有具体文件能拿到。想公开文件又不想让人翻目录,就写不带参数的版本。

性能:50 次请求 p50 0.9 毫秒

对首页连发 50 次请求,最快 0.8 毫秒,中位 0.9 毫秒,最慢 12.4 毫秒。最慢那次是首次建立的连接开销。

5 MB 的文件下载 0.01 秒完成,换算 618.7 MB/s。这是本地回环的数字,只说明它没有额外拷贝开销,不代表公网带宽。

指标数值
首页体积133 字节
50 次请求最快0.8 毫秒
50 次请求中位0.9 毫秒
50 次请求最慢12.4 毫秒
5 MB 下载0.01 秒

首次运行在 AppData 建了三个文件

第一次跑 caddy run,它在 C:\Users\用户名\AppData\Roaming\Caddy 建了目录,里面三个小文件。

autosave.json 存的是上一次成功启动的配置,268 字节。instance.uuid 是这个实例的唯一标识,36 字节。last_clean.json 记录上次清理证书存储的时间,110 字节。

文件字节作用
autosave.json268上次启动的配置快照
instance.uuid36实例标识
last_clean.json110证书存储清理时间

证书和密钥也在这里

开了 HTTPS 之后,申请到的证书存在同一个目录下的 certificates 子目录里。换机器时把这个目录拷走,就不用重新申请。

想整个搬走做绿色版,加 XDG_DATA_HOME 或者配置里指定 storage 路径,别让它写 AppData。

admin API 能在线改配置

配置里写了 admin 127.0.0.1:2019,起来之后 2019 端口就是一个管理接口。GET /config/ 返回当前生效的完整配置,往返 1.2 毫秒。

返回两个顶层键:admin 和 apps。apps 下面是 http 和 tls 两棵配置树。想改路由不用重启,直接 POST 到对应路径就行。

这个接口默认只监听本地。要远程管理得显式改成对外地址,同时会失去「本地免认证」的保护,得自己加一层防护。

几个真踩过的坑

症状原因处理
启动报 bind 错误直接退出80 或 443 被占用全局块设 http_port / https_port
访问目录 404file_server 没加 browse补上 browse 参数
改了配置不生效没重启或没调 reloadcaddy reload 或重启进程
中文文件名乱码系统编码与响应头不一致确认浏览器与目录编码一致
配置改了没反应用了别的 Caddyfile命令里显式 --config

第一条最容易卡住新手。它不会提示「80 端口被占」,只报一个 bind 失败然后进程退出,用 netstat 查一遍才知道是谁占了。

什么场景值得上

你的情况结论
把本地目录挂成网页给别人取合适,两行配置
给内部服务加一层反向代理合适,reverse_proxy 一行搞定
要自动 HTTPS合适,这是它的招牌能力
要图形界面点配置不合适,它只有命令行和 API
要 PHP 或 Java 应用服务器不合适,它只做转发和静态文件

它的定位是「前面那一层」。静态文件、反向代理、证书续期和 HTTP 到 HTTPS 跳转,这些归它管。业务逻辑放后面的服务里。

写配置的手感比 Nginx 好,因为 Caddyfile 的层级浅。代价是生态小一些,遇到冷门需求查资料不如 Nginx 容易。