运维知识
悠悠
2026年9月26日

Caddy 到底是什么?和 Nginx 有什么区别?附 Amazon Linux 2023 安装实战

晚上 10 点,监控突然报警:接口 5xx 错误率持续升高。浏览器访问域名,HTTPS 证书正常,页面却返回 502 Bad Gateway。

后端服务明还活着,在宿主机上执行 curl http://127.0.0.1:8080 也能正常响应。有人怀疑证书续期失败,有人准备重启代理,还有人开始检查应用代码。

但 Caddy 日志中的关键证据只有一句:

dial tcp 127.0.0.1:8080: connect: connection refused

看到这里先别急着重启。

很多人知道 Nginx,却没真正弄明白 Caddy 是什么。有人把它看成自动申请 HTTPS 证书的工具,也有人认为它只是“配置更简单的 Nginx”。

这些理解都不算错,但并不完整。下面我会讲清楚 Caddy 的作用、它和 Nginx 的区别,并以 Amazon Linux 2023 为例,完成从安装、启动、配置 HTTPS 到故障排查的全过程。

Caddy 到底是什么?

Caddy 是一个开源 Web 服务器,同时可以作为反向代理、负载均衡器和 HTTPS 入口网关。

对于大多数网站和 API 服务,Caddy 通常位于用户与业务应用之间:

用户浏览器
    ↓
DNS 与 EC2 安全组
    ↓
Caddy:HTTPS、证书、日志、压缩、请求转发
    ↓
Java、Go、Python、Node.js 等业务服务

假设 Java 服务监听在 127.0.0.1:8080,我们希望用户通过 https://api.example.com 访问,而不是直接暴露 8080 端口。

使用 Caddy,只需要:

api.example.com {
    reverse_proxy 127.0.0.1:8080
}

这段配置主要完成四件事:

  • 监听网站的 HTTP 和 HTTPS 请求;
  • 为域名申请并管理 TLS 证书;
  • 将 HTTP 请求自动跳转到 HTTPS;
  • 把请求转发给 8080 端口的业务服务。

Caddy 不是业务应用,也不会替代 Java、Go 或 Python。它更像站在应用前面的入口接待员:先接收外部请求,处理域名、协议和证书,再把请求交给正确的后端服务。

它还可以直接提供静态文件:

www.example.com {
    root * /srv/www
    file_server
}

也可以代理多个上游:

api.example.com {
    encode zstd gzip

    reverse_proxy app01:8080 app02:8080 {
        health_uri /healthz
        health_interval 10s
        health_timeout 2s
    }
}

一句话记住:

Caddy 是把 HTTPS、Web 服务和反向代理做得更自动化的入口服务器,但自动化并不能替代对 DNS、网络和上游服务的理解。

Caddy 和 Nginx 有什么区别?

Caddy 和 Nginx 都能提供静态网站、反向代理、TLS 终止、压缩、访问日志和负载均衡。普通 Web 系统中,两者能做的事情有很大重叠。

真正的区别主要体现在 HTTPS 管理、配置方式、生态成熟度和复杂场景控制能力上。

对比项CaddyNginx
核心特点自动 HTTPS、配置简洁成熟稳定、生态丰富
常用配置Caddyfile,也支持原生 JSONNginx 指令式配置
HTTPS默认自动申请、续签证书通常配合 Certbot 等工具
HTTP 跳转 HTTPS默认自动处理通常手工配置
配置变更支持平滑 reload 和管理 API通常检查后执行 reload
结构化日志原生支持较方便一般需要自行定义日志格式
复杂缓存与重写常见需求够用历史案例和配置经验更多
扩展生态模块化,第三方模块需定制构建官方及第三方模块积累更深
学习成本常见场景上手较快复杂规则需要更多经验
生产积累已可用于生产,但中文案例相对少大规模生产实践非常丰富

同样代理一个服务,Nginx 通常这样配置:

server {
    listen 443 ssl;
    server_name api.example.com;

    ssl_certificate     /etc/letsencrypt/live/api.example.com/fullchain.pem;
    ssl_certificate_key /etc/letsencrypt/live/api.example.com/privkey.pem;

    location / {
        proxy_pass http://127.0.0.1:8080;
    }
}

证书往需要使用 Certbot 或其他 ACME 客户端申请、续签,并在续签后重新加载 Nginx。

Caddy 的常用配置则是:

api.example.com {
    reverse_proxy 127.0.0.1:8080
}

只要域名解析、端口连通性和存储权限满足要求,Caddy 就会自动管理证书和 HTTPS 跳转。

但不能因此得出“Caddy 一定比 Nginx 好”的结论。

如果是新建中小型网站、API 服务、个人博客或内部系统,主要需求是 HTTPS 和常规反向代理,Caddy 通常更省事。

如果已有成熟的 Nginx 配置,大量依赖复杂的 location、缓存、重写规则、特定模块或现有运维平台,继续使用 Nginx往更稳妥。

性能也不能只看脱离业务的跑分。Nginx 在高并发场景中积累深厚,Caddy 在常规网站和 API 场景中的性能通常也足够。真正的结论应来自相同硬件、TLS 参数、日志配置和业务请求模型下的压测。

Amazon Linux 2023 应该怎样安装 Caddy?

下面使用的系统是:

NAME="Amazon Linux"
VERSION_ID="2023"
PRETTY_NAME="Amazon Linux 2023.12.20260918"
ID_LIKE="fedora"

需要特别说明:虽然 Amazon Linux 2023 的 ID_LIKE 包含 fedora,但它并不等于 Fedora。

Caddy 官方安装文档明确提供了 Fedora、RHEL 和 CentOS 的 COPR 软件包方式,却没有把 Amazon Linux 2023 列为该软件源的直接支持对象。为了避免仓库识别、依赖关系和系统升级兼容问题,这里采用官方发布的静态二进制,并手工配置 systemd。

这种方式步骤稍多,但安装内容和版本都更可控。

安装前先确认架构和网络条件

下面的命令均为只读检查:

cat /etc/os-release
uname -m
curl -I https://github.com

EC2 常见架构对应关系如下:

x86_64  → amd64
aarch64 → arm64

还要提前确认:

  • 域名的 A 记录指向 EC2 的公网地址;
  • 建议绑定 Elastic IP,避免实例重启后公网地址变化;
  • EC2 安全组允许公网访问 TCP 80 和 443;
  • SSH 的 22 端口只允许可信管理地址访问;
  • 若配置 AAAA 记录,必须保证 IPv6 链路真实可用;
  • 8080 等业务端口不要无必要地暴露到公网。

开放安全组属于网络访问策略变更。80 和 443 可以根据业务需要对公网开放,但不要把 22、2019 或后端业务端口一并开放。

下载并校验官方二进制

当前已经进入 root 环境,以下命令不再重复添加 sudo。

先安装下载和解压工具:

dnf install -y curl tar

安装软件会改变系统包状态。生产机器应先确认变更窗口,并保留当前软件包清单。

接下来设置要安装的固定版本。下面的 2.10.2 是一个明确的安装示例;实际执行前,应在 Caddy 官方发布页面确认目标版本,并经过测试后再修改该变量,不建议在生产环境自动追踪 latest:

CADDY_VERSION="2.10.2"

case "$(uname -m)" in
  x86_64)
    CADDY_ARCH="amd64"
    ;;
  aarch64)
    CADDY_ARCH="arm64"
    ;;
  *)
    echo "不支持的 CPU 架构:$(uname -m)"
    exit 1
    ;;
esac

CADDY_FILE="caddy_${CADDY_VERSION}_linux_${CADDY_ARCH}.tar.gz"
CADDY_URL="https://github.com/caddyserver/caddy/releases/download/v${CADDY_VERSION}"

mkdir -p /tmp/caddy-install
cd /tmp/caddy-install

curl -fLO "${CADDY_URL}/${CADDY_FILE}"
curl -fLO "${CADDY_URL}/caddy_${CADDY_VERSION}_checksums.txt"

curl 使用了 -f,遇到 404 或服务器错误时会直接失败。如果下载失败,先核对版本号和 CPU 架构,不要继续解压不存在或不完整的文件。

校验 SHA-512 摘要:

grep " ${CADDY_FILE}$" \
  "caddy_${CADDY_VERSION}_checksums.txt" \
  | sha512sum -c -

正常结果应包含:

caddy_2.10.2_linux_amd64.tar.gz: OK

如果没有匹配结果或校验失败,禁止继续安装。应删除本次下载文件,重新核对版本、文件名和下载来源。

解压并安装:

tar -xzf "${CADDY_FILE}"
install -o root -g root -m 0755 caddy /usr/bin/caddy

caddy version
caddy list-modules

image-20260926225339027

如果系统中已经存在 /usr/bin/caddy,覆盖前务必备份旧二进制和版本信息:

cp -a /usr/bin/caddy \
  "/usr/bin/caddy.bak-$(date +%Y%m%d-%H%M%S)"

不要在没有备份和验证的情况下直接替换生产环境正在运行的二进制。

创建运行用户和数据目录

Caddy 不需要以 root 身份长期运行。创建独立系统用户:

getent group caddy >/dev/null \
  || groupadd --system caddy

id caddy >/dev/null 2>&1 \
  || useradd \
       --system \
       --gid caddy \
       --home-dir /var/lib/caddy \
       --create-home \
       --shell /sbin/nologin \
       caddy

创建配置、数据和日志目录:

install -d -o root  -g caddy -m 0750 /etc/caddy
install -d -o caddy -g caddy -m 0750 /var/lib/caddy
install -d -o caddy -g caddy -m 0750 /var/log/caddy

/var/lib/caddy 必须持久化。这里会保存自动 HTTPS 需要的证书、私钥和账户状态,不能把它当作普通缓存随意删除。

创建 systemd 服务

写入 /etc/systemd/system/caddy.service:

[Unit]
Description=Caddy Web Server
Documentation=https://caddyserver.com/docs/
After=network-online.target
Wants=network-online.target

[Service]
Type=notify
User=caddy
Group=caddy
Environment=XDG_DATA_HOME=/var/lib/caddy
Environment=XDG_CONFIG_HOME=/var/lib/caddy
ExecStart=/usr/bin/caddy run --environ --config /etc/caddy/Caddyfile
ExecReload=/usr/bin/caddy reload --config /etc/caddy/Caddyfile --force
TimeoutStopSec=5s
LimitNOFILE=1048576
PrivateTmp=true
ProtectSystem=full
ProtectHome=true
NoNewPrivileges=true
AmbientCapabilities=CAP_NET_ADMIN CAP_NET_BIND_SERVICE
CapabilityBoundingSet=CAP_NET_ADMIN CAP_NET_BIND_SERVICE

[Install]
WantedBy=multi-user.target

CAP_NET_BIND_SERVICE 允许非 root 进程监听 80 和 443。管理接口应保持在本机,不要把 2019 端口开放到 EC2 公网安全组。

执行以下命令让 systemd 读取服务文件:

systemctl daemon-reload

此时先不要启动,先完成最小配置和配置验证。

先用 HTTP 完成最小验证

# 创建配置目录
mkdir -p /etc/caddy

# 编辑或创建 Caddyfile 文件
nano /etc/caddy/Caddyfile

在没有准备好域名时,可以先使用一个纯 HTTP 配置:

:80 {
    respond "Caddy on Amazon Linux 2023 is running" 200
}

检查配置:

caddy validate \
  --config /etc/caddy/Caddyfile \
  --adapter caddyfile

image-20260926225949845

验证成功后启动:

systemctl enable --now caddy
systemctl status caddy --no-pager

这是有状态操作,会启动服务并监听端口。执行前确认 80 端口没有被 Nginx、Apache 或其他程序占用:

ss -lntp | grep -E ':(80|443)\s'

本机验证:

curl -i http://127.0.0.1/
journalctl -u caddy --since "10 minutes ago" --no-pager

正常情况下应返回 HTTP 200 和测试文本。

如果出现 address already in use,说明端口已被其他程序占用。不要直接停止未知进程,应先通过 ss -lntp 查清程序和业务归属。

配置域名、HTTPS 和反向代理

确认域名已经解析到 EC2 公网地址,安全组也已开放 80、443 后,把配置改为:

{
    email ops@example.com
    admin localhost:2019

    log {
        output file /var/log/caddy/caddy.log {
            roll_size 100MiB
            roll_keep 10
            roll_keep_for 720h
        }
        format json
        level INFO
    }
}

api.example.com {
    encode zstd gzip

    reverse_proxy 127.0.0.1:8080 {
        health_uri /healthz
        health_interval 10s
        health_timeout 2s
        lb_try_duration 5s
    }

    log {
        output file /var/log/caddy/access.log {
            roll_size 100MiB
            roll_keep 10
            roll_keep_for 720h
        }
        format json
    }
}

api.example.com、邮箱和上游端口必须替换为实际值。

如果应用与 Caddy 在同一台 EC2 上,并监听 127.0.0.1:8080,这份配置可以直接转发。如果 Caddy 与应用分别运行在不同容器中,就不能使用 127.0.0.1 指向另一个容器,应使用容器服务名。

修改前先备份:

cp -a /etc/caddy/Caddyfile \
  "/etc/caddy/Caddyfile.bak-$(date +%Y%m%d-%H%M%S)"

检查业务服务:

curl -sS -i http://127.0.0.1:8080/healthz
ss -lntp | grep ':8080'

验证并平滑加载配置:

caddy validate \
  --config /etc/caddy/Caddyfile \
  --adapter caddyfile

systemctl reload caddy
systemctl status caddy --no-pager

随后检查公网访问:

curl -I https://api.example.com
journalctl -u caddy --since "10 minutes ago" --no-pager

caddy validate 成功只代表配置可以加载,不代表 DNS、EC2 安全组、证书签发和上游服务一定正常。

变更后应持续观察:

  • HTTPS 证书是否成功签发;
  • HTTP 是否自动跳转到 HTTPS;
  • 4xx、5xx 比例是否异常;
  • 上游是否出现连接拒绝或超时;
  • 接口 P95、P99 延迟是否上升;
  • /var/lib/caddy 和日志磁盘空间是否正常。

若新配置导致异常,恢复最近一次备份,重新执行 caddy validate,确认无误后再次 reload。

一个 502 故障,暴露了容器网络误区

下面用一个脱敏后的典型场景说明,时间、域名和监控数据均为示例。

21:47,监控发现 api.example.com 的 5xx 错误率在两分钟内从 0.2% 升至 63%,接口 P95 延迟由 180 毫秒升至 5 秒。TLS 握手成功,证书有效,但代理请求全部返回 502。

Caddy 和应用分别运行在两个 Docker Compose 容器中,配置却写成:

api.example.com {
    reverse_proxy 127.0.0.1:8080
}

宿主机执行下面的只读检查能够返回 HTTP 200:

curl -sS -i http://127.0.0.1:8080/healthz

有人因此准备重启 Caddy。但这个证据只能证明宿主机可以访问映射端口,不能证明 Caddy 容器也能访问该地址。

继续检查日志:

docker compose logs --since=20m caddy

其中持续出现:

{
  "level": "error",
  "status": 502,
  "err": "dial tcp 127.0.0.1:8080: connect: connection refused"
}

这说明请求已经到达 Caddy,失败发生在连接上游阶段。证书、公网入口和浏览器缓存因此被排除。

接着检查容器状态和服务名解析:

docker compose ps
docker compose exec caddy getent hosts app
docker compose exec caddy \
  wget -S -O - http://app:8080/healthz

通过 app:8080 可以返回 HTTP 200,根因至此形成完整证据链:Caddy 容器中的 127.0.0.1 指向 Caddy 容器自己,不是宿主机,也不是应用容器。

正确配置应该是:

api.example.com {
    reverse_proxy app:8080
}

宿主机能通,不代表真实代理链路能通。排查上游时,必须在 Caddy所在的网络空间中验证。

Amazon Linux 2023 上线避坑清单

  • 务必使用固定版本安装。生产环境自动追踪 latest 会让升级内容不可控。
  • 务必校验下载文件。校验失败可能意味着文件损坏、版本错误或下载来源异常。
  • 不要因为 ID_LIKE=fedora 就默认所有 Fedora COPR 包都兼容 Amazon Linux 2023。
  • 不要让 Caddy 长期以 root 身份运行。独立用户配合低端口能力即可满足常见需求。
  • 务必持久化 /var/lib/caddy。删除该目录可能丢失证书、私钥和 ACME 账户状态。
  • 禁止把管理端口 2019 开放到公网,否则可能扩大配置接口的攻击面。
  • 不要把 EC2 的 22 和业务端口全部开放给 0.0.0.0/0。SSH 应限制可信来源,上游端口优先仅在本机或私网监听。
  • 务必确认域名的 A、AAAA 记录都有效。错误的 IPv6 记录会让部分客户端进入不可达链路。
  • 千万别看到 502 就直接重启。重启不能修复错误的上游地址,还可能破坏现场证据。
  • 不要使用容器内的 127.0.0.1 指向另一个容器,应使用服务名或经过验证的内部地址。
  • 务必分别保留访问日志和运行日志。只有 HTTP 状态码,很难判断故障发生在证书、路由还是上游连接阶段。
  • 务必在修改前备份二进制、服务文件和 Caddyfile,并在小流量范围验证后再扩大变更。
  • 不要为了配置更短而仓促替换稳定的 Nginx。迁移前应盘点缓存、重写、模块、监控和发布流程。
  • 卸载时不要直接删除 /var/lib/caddy。先停止并禁用服务,保留证书数据和旧配置,以便恢复。

Caddy 不是一个单纯的证书工具,而是能够承担 HTTPS、静态文件、反向代理和负载均衡的 Web 服务器。

它和 Nginx 并不是谁淘汰谁的关系:Caddy更重视自动 HTTPS和简洁配置,Nginx则拥有更深的生产积累和复杂场景生态。

对于 Amazon Linux 2023,我更建议使用经过校验的官方静态二进制,配合独立用户和 systemd 运行。这样既能避开非直接支持的软件仓库,也方便固定版本、审计变更和回滚。

今天就可以做一件事:画出“用户—DNS—EC2 安全组—Caddy—业务服务”的真实请求链路,再从 Caddy 所在的网络空间访问一次上游。这个简单动作,往能提前发现大量“宿主机明能通,代理为什么不通”的问题。

如果这篇文章对你有帮助,欢迎关注、点赞、在看,也可以转发给正在使用 Caddy 或准备从 Nginx 迁移的同事。

公众号:耕云躬行录

个人博客:躬行笔记

文章目录

博主介绍

热爱技术的云计算运维工程师,Python全栈工程师,分享开发经验与生活感悟。
欢迎关注我的微信公众号@运维躬行录,领取海量学习资料

微信二维码