一台全新的 VPS,域名已指向它,只差一条命令就能跑起一个 Web 服务器。你接下来敲的命令要么装 Caddy,要么装 Nginx,而这一个决定,决定了在这台机器的整个生命周期里你要在 TLS 上花多少时间。那么:VPS 上的 Caddy 与 Nginx,你该装哪一个?
接下来是同样的三种配置在两个工具中并排呈现,附上报告的内存数字、通配符证书的坑,以及如果你已经在用 Nginx 时的实用迁移说明。
简短版本
- 结论: 对于大多数全新 VPS 工作负载,选 Caddy,尤其适合独立开发者、小团队以及“一次配置、无需操心”的 TLS。当你需要它的模块生态、显式调优、团队已有的专业积累,或尽可能小的内存占用时,选 Nginx。
- 自动 HTTPS: Caddy 自己获取并续期证书。无需 Certbot,无需 cron,无需 reload 钩子。Nginx 需要 Certbot(或另一个 ACME 客户端)以及围绕它的续期自动化。
- Memory: Nginx 更精简,得益于用 C 而非 Go 编写。在现代套餐上,这个差距很少能决定什么;具体数字见下表。
- 需要注意的是: 对于通配符,Caddy 并非零配置。像 *.example.com 这样的名称需要 DNS 质询,这意味着要一个插件和一个 API 令牌。
整个对比一屏看尽:
| Caddy | Nginx | |
|---|---|---|
| 语言 | Go | C |
| 自动 HTTPS | 内置(Let's Encrypt + ZeroSSL) | 无;需要 Certbot 或另一个 ACME 客户端 |
| 配置冗长度 | 极简(每个站点几行) | 显式且冗长 |
| HTTP/3 | 在启用 HTTPS 时默认开启 | 自 1.25.0 起可用;必须在 Nginx 配置中启用。源码构建需要 --with-http_v3_module. |
| 报告的空闲内存 | 15-25 MB | 2-8 MB |
| 1,000 个连接时报告的内存 | 80-120 MB | 50-80 MB |
| 模块生态 | 较小,通过 xcaddy 扩展 | 庞大且成熟 |
| 许可 | Apache 2.0 | BSD-2-Clause |
这些内存区间来自 一次第三方 VPS 测试 ,应当被视为方向性参考,而非通用要求。实际占用取决于软件版本、已启用的模块、日志记录、流量以及测试方法。版本和许可信息来自各项目的官方仓库。
Caddy 的自动 HTTPS(以及它实际取代了什么)
Caddy 自行获取并续期 TLS 证书。把一个公开域名指向这台机器,运行 Caddy,它就会从 Let's Encrypt 或 ZeroSSL 取得证书,然后在后台续期。无需 Certbot,无需 cron 任务,无需续期后的 reload 钩子。这就是一句话概括的 Caddy 自动 HTTPS,也正是人们转投它的全部理由。
在底层,Caddy 使用 HTTP-01(port 80)或 TLS-ALPN-01(port 443)质询 来证明域名所有权,随后无需任何第二个工具介入即可保持证书有效。
Nginx 的等效做法则要用一个独立的 ACME 客户端。使用常见的 certbot --nginx 工作流,Certbot 可以获取并安装证书,然后 在续期时复用相同的插件和已保存的选项。大多数 Certbot 安装还会包含一个计划任务,它会自动 certbot renew 运行。
如果你使用 certbot certonly 或另一个只把续期文件写入磁盘的 ACME 客户端,就添加一个 部署钩子 ,让它在续期成功后重新加载 Nginx。这套方案可行,但它比 Caddy 留下了更多活动部件:Web 服务器、ACME 客户端、续期调度器以及任何部署钩子仍是各自独立的组件。
Caddy 的运维优势在于,证书签发、部署、续期以及 HTTP 到 HTTPS 的重定向都集成在服务器本身之中。默认情况下,当证书大约 还剩三分之一有效期时,Caddy 便开始尝试续期,对于 90 天的证书就是剩 30 天时,除非证书颁发机构指定了不同的续期窗口。
小贴士: Caddy 默认的 ACME 质询需要在 port 80 或 port 443 上可从公网访问:HTTP-01 使用 port 80,而 TLS-ALPN-01 使用 port 443。如果 port 80 被封而 443 开放,TLS-ALPN 仍可能奏效;如果这台机器不面向互联网,就用 DNS-01,和下文的通配符证书一样。
配置文件并排对照
下面是三种常见的 VPS 配置——HTTPS 反向代理、静态文件服务和基本认证——分别用两个工具编写。Caddy 示例包含自动 HTTPS。Nginx 示例假定证书已经配置就绪,且静态文件和基本认证示例只展示 HTTPS 服务块。如果你想要等效的 HTTP 到 HTTPS 行为,复用第一个示例中的 port 80 重定向块即可。
反向代理到 port 3000 上的本地应用:
Caddyfile
example.com {
reverse_proxy localhost:3000
}
nginx.conf
server {
listen 443 ssl;
server_name example.com;
ssl_certificate /etc/letsencrypt/live/example.com/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/example.com/privkey.pem;
location / {
proxy_pass http://localhost:3000;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
}
}
server {
listen 80;
server_name example.com;
return 301 https://$host$request_uri;
}
Nginx 块中的 TLS 行假定 Certbot 已经运行过。对于像上面这样的 HTTP 上游,Caddy 会把传入的 Host 头透传过去,并默认设置 X-Forwarded-For, X-Forwarded-Proto,以及 X-Forwarded-Host 默认情况下。使用 Nginx 时,当上游需要原始主机、协议方案和客户端地址链时,你通常要显式添加代理头。这就是这一权衡的缩影:Caddy 提供了实用的代理默认值,而 Nginx 让更多这类行为交由你显式指定。
静态文件服务:
Caddyfile
example.com {
root * /var/www
file_server
}
nginx.conf
server {
listen 443 ssl;
server_name example.com;
ssl_certificate /etc/letsencrypt/live/example.com/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/example.com/privkey.pem;
root /var/www;
index index.html;
location / {
try_files $uri $uri/ =404;
}
}
基本认证,用用户名和密码把所有内容保护起来:
Caddyfile
example.com {
basic_auth {
Bob $2a$14$Zkx19XLiW6VYouLHR5NmfOFU0z2GTNmpkT/5qqR7hx4IjWJPDhjvG
}
reverse_proxy localhost:3000
}
nginx.conf
server {
listen 443 ssl;
server_name example.com;
ssl_certificate /etc/letsencrypt/live/example.com/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/example.com/privkey.pem;
auth_basic "Restricted";
auth_basic_user_file /etc/nginx/.htpasswd;
location / {
proxy_pass http://localhost:3000;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
}
}
两个工具都在带外对密码做哈希。Caddy 使用 caddy hash-password;Nginx 使用 htpasswd 来构建 .htpasswd 文件。顺便一提,在当前版本的 Caddy 中,这个指令是 basic_auth 。它原本叫 basicauth ,直到 v2.8.0 将其重命名,正如 Caddy basic_auth 文档中所述,旧教程至今仍让人在这上面栽跟头。
小贴士: Caddyfile 里的那串哈希并不是密码。它是来自
caddy hash-password的 bcrypt 输出。运行该命令,把它打印出来的内容粘贴进去即可。Caddy 拒绝在配置中使用明文密码,这是正确的默认行为,也是初次遇到时的一个小意外。
这些配置本身就说明了问题。Caddy 把 TLS、合理的代理头和一个重定向折叠进寥寥几行;Nginx 则显式而冗长,把每一个旋钮都交到你手上。如果你在 Nginx 上摸爬滚打多年,这份冗长就是肌肉记忆,而那份控制力正是它的意义所在。如果你没有,那 Caddyfile 就是一份你能装进脑子里的配置。实用的要点很简单:Caddy 的配置一眼就更好读,而 Nginx 给你更显式的控制。
性能与内存:审慎地解读基准测试
已发布的测试大体指向同一个方向:Nginx 通常占用更少的内存,在原始吞吐量上也常常领先,但这份优势的大小在很大程度上取决于环境。
In 一次第三方四核虚拟机测试中,Nginx 达到约每秒 48,000 个请求,而 Caddy 约为 42,000。同一测试报告的 HTTPS p99 延迟,Nginx 为 2.1 ms,Caddy 为 2.4 ms。请把这些当作来自单一配置的结果,而非普遍适用的性能差距。
对比表中的内存区间来自一次 独立的 VPS 测试。另一项 在 50,000 个并发连接下的合成测试 报告 Nginx 为 145 MB、Caddy 为 520 MB,但该测试使用了截然不同的硬件和工作负载条件。其绝对数值不应与上面的 VPS 数字直接对比。
可靠的结论要窄得多:Nginx 通常内存占用更小,在高吞吐或高并发工作负载下往往领先。对于一台普通的中小型 VPS 反向代理,两者通常都足够快,因此运维上的简单往往才是更有用的决定因素。
本节要点: 根据运维来选择,除非你的服务器受内存约束,或你自己的负载测试表明代理吞吐量是瓶颈。
通配符证书的坑(Caddy 并非总是零配置)
Caddy 可以自动化通配符证书,但不能用它默认的 HTTP-01 或 TLS-ALPN-01 质询。一张针对 *.example.com 的证书需要 DNS-01 验证,这是 Let's Encrypt 对通配符证书的强制要求。这意味着需要一个 DNS 提供商插件(通过 xcaddy 编入你的 Caddy 二进制文件)外加一个用于你 DNS 主机的 API 令牌,并在 tls 块中配置。这可不是 Caddy 所宣传的“敲一行然后走人”的那种故事。
这会坑到那些把众多服务放在自己掌控的真实域名之下的家庭实验室用户,比如 *.home.example.com,并以为通配符签发会像 app.example.com那样自动。对于像 *.homelab.internal这样纯内部的名称,应把它当作本地/内部 PKI 的范畴,而不是公开的 Let's Encrypt 通配符。说得精确些:Caddy 处理通配符没问题,只是它不用默认质询来处理,而且这套配置比单域名的情形要更进一步。Nginx 在这一点上处境相同,因为 DNS-01 的要求来自 Let's Encrypt,而不是服务器。
如果你想要一个 GUI:Nginx Proxy Manager(简短的题外话)
Nginx Proxy Manager 与上面两个工具是完全不同的东西,值得用一段来讲,因为这个名字常让人混淆。NPM 是套在 Nginx 之上的 GUI 封装:它通过 port 81 上的 Web 界面管理反向代理规则和 Let's Encrypt 证书。它不是 Nginx 核心,配置方式也和 Nginx 核心不同。
这个权衡就是常见的“点击 vs 配置文件”之争。NPM 是那个省事的按钮,直到你偏离顺遂之路。它的配置通过一个应用数据库来管理,而不是一份手工编辑的单一配置文件。 默认的 Docker 部署使用 SQLite,而 MySQL/MariaDB 和 PostgreSQL 是受支持的外部数据库选项。这一差异也影响可移植性:一套 Caddy 配置往往只需复制一份 单一的 Caddyfile就能迁移,而一套 Nginx Proxy Manager 部署则需要保留它的 应用数据和数据库 。如果你确实更喜欢点击而非编辑,且你的部署保持简单,那 NPM 是个不错的选择。但对于基础设施即代码的工作流,它就是错误的选择。
从 Nginx 迁移到 Caddy(哪些能对应过去、哪些不能)
如果你已经在用 Nginx 并在权衡是否迁移,先把对自动化的期望降下来:确实有一个 Caddy 的 NGINX 配置适配器,但它并不完整,不应被当作可靠的一步到位迁移路径。从 Nginx 到 Caddy 的迁移大多是手动重写,而其中大部分内容都会变得更短。
哪些内容能对应过去并变得更简单,依据 Caddy 社区的转换指南:
- 对于 HTTP 上游,
reverse_proxy会把传入的Host头透传过去,并 默认设置标准的 X-Forwarded-* 头,因此大部分那些proxy_set_header行都会消失。 - PHP 从一个带有
try_files加fastcgi_pass外加一堆参数的 location 块,收缩成单个php_fastcgi指令。 - 在 Caddy v2 中,WebSocket 的处理是自动的。如果某个教程让你添加一个单独的
websocket指令,那是 Caddy v1 的遗留产物。忽略它。
哪些内容不能自动对应过去:任何绑定于某个 Caddy 没有的特定 Nginx 模块的东西、需要你重新思考而非照搬的复杂 rewrite 和 location 逻辑,以及通配符证书配置——它们会把你重新带回上一节的 DNS 质询配置。为这些模块和重写留出工时;其余部分通常在行数上是净减少的。
你该装哪一个?(结论)
你已经看过了配置、数字、通配符的坑以及迁移成本,那么结论就在这里。如果你是独立开发者或小团队、这是一次全新的 VPS 部署、你想要“一次配置、无需操心”的 TLS、你在跑带简单路由的 Docker,或者你只是想要一份能装进肌肉记忆的配置,那就装 Caddy。这适用于读到这里的大多数人。
如果你需要细粒度控制或它成熟生态中的某个特定模块、你在从一台受内存约束的服务器上榨取性能、你在做高并发的静态文件服务,或者你的团队已经拥有深厚的 Nginx 专业积累和一堆能用的配置,那就装 Nginx。这些都是扎实的理由,如果其中之一正是你的情况,那 Nginx 就是正确的选择。这并不是那种“更老的工具就是错的工具”的情形。
无论你最终选哪一个,下一步都是把它装到机器上。两者 Caddy 和 Nginx 都可以在我们的应用市场中一键部署,因此你可以跳过安装工作,直接上手 Caddyfile 或服务块。对于低流量的单站点部署,1 GB VPS 是一个合理的起点,但要按代理背后的应用和流量来给服务器选配,而不是只按代理本身。如果你把 Caddy 用作自托管服务的前门,它可以置于一套 Prometheus 和 Grafana 监控栈 或一套 Uptime Kuma 部署 之前,而无需单独的 TLS 工具。
本节要点: 选 Caddy,除非你有某个明确指向 Nginx 的具体理由。
常见问题
Caddy 会取代 Certbot 吗?
会。Caddy 能自行获取并续期公开证书,包括通配符证书,因此不需要 Certbot。 通配符需要 DNS-01 验证,这意味着要配置一个兼容的 DNS 提供商模块和 API 凭证。
Caddy 比 Nginx 占用更少内存吗?
不。Nginx 通常内存占用更小。 一次第三方 VPS 测试 报告 Nginx 空闲时为 2-8 MB,Caddy 为 15-25 MB,但这些数字是特定工作负载下的,而非固定的内存要求。这一差别在运行多个服务、受内存约束的服务器上最为要紧。
Caddy 比 Nginx 更快吗?
取决于工作负载。对于典型的 VPS 反向代理流量,两者通常都足够快。在 所引用的测试中,Nginx 在原始吞吐量和内存效率上领先,但差距的大小会随 硬件、流量模式和并发级别而大幅变化。没有一个适用于每一种部署的单一百分比。
Caddy 支持通配符 SSL 证书吗?
支持。一张通配符证书,比如针对 *.example.com 的证书需要 DNS-01 验证的证书。一旦 Caddy 拥有兼容的 DNS 提供商模块和 API 凭证,它就能自动获取并续期该通配符证书。
Nginx Proxy Manager 和 Nginx 是一回事吗?
不是。Nginx Proxy Manager 是套在 Nginx 之上的 GUI 封装,它把配置存储在一个应用数据库中,通过 port 81 上的 Web UI 运行,并借由该界面管理反向代理主机和证书。Nginx 核心则用文本文件配置,本身没有 GUI。
我什么时候该用 Nginx 而不是 Caddy?
当你需要细粒度控制、它成熟生态中的某个特定模块、在受内存约束的服务器上榨干每一 MB、高并发的静态文件服务,或者你的团队已经拥有深厚的 Nginx 专业积累时,选 Nginx。