返回博客
八月 19, 2026指南

如何安装带自动 HTTPS 的 Caddy Web 服务器

从官方仓库在 Ubuntu 上安装 Caddy,为静态站点和反向代理编写 Caddyfile,理解自动证书、systemd、日志,以及从 Nginx 迁移时的常见错误。

如何安装带自动 HTTPS 的 Caddy Web 服务器

Caddy 是默认获取并续期 TLS 证书的 Web 服务器。对于托管一两个域名的小型 VPS,这去掉了整整一类 Certbot 定时器和 Nginx 片段文件。配置语言(Caddyfile)很短。反向代理、gzip 和 HTTP/2 是普通功能,不是周末加班的额外模块。

对某些团队 Nginx 仍是正确选择:你已经有经过实战的配置,或需要非常特定的模块。本指南面向另一种常见情况——你想要在全新 Hiddence VPS 上能用的 HTTPS,而不必记住 include 片段。我们将从官方 apt 仓库安装 Caddy,解释它如何与 Let's Encrypt 对话,提供静态站点,代理本地应用,托管多个域名,查看日志,并处理与 Apache 或旧 Nginx 抢端口 80 的常见情况。

什么时候 Caddy 很合适

自动 HTTPS 是标题,但日常收益是更少的活动部件。Caddy 监听 80 和 443,把 HTTP 重定向到 HTTPS,并把证书存在数据目录。你仍然需要指向 VPS 的域名。你仍然需要不破坏 ACME(防火墙 80/tcp,没有别的进程偷走 :80)。通配符证书需要 DNS 提供商模块——那比单主机证书更长的一条路。

  • 自动 HTTP→HTTPS 和证书续期
  • 可读的 Caddyfile,而不是长长的 server 块
  • 胜任 Node、Python、额外配置的 PHP-FPM,或 Docker 后端的反向代理
  • HTTP/2 和现代 TLS 默认,不必 Spreadsheet 密码套件
  • 官方软件包提供的 systemd 单元

要求

在 Caddy 能证明 ACME HTTP-01 之前,域名必须解析到这台 VPS。如果 DNS 仍在传播,Caddy 会签发失败并重试;看起来像「Caddy 坏了」,其实只是 DNS。如果 Apache 或 Nginx 占用 80/443,先停掉它们。

  • Ubuntu 22.04 或 24.04
  • 指向 VPS IP 的域名 A 记录(如果用 IPv6 还有 AAAA)
  • 端口 80 和 443 空闲并已在防火墙中允许
  • root 或 sudo

步骤 1:从官方仓库安装 Caddy

如果你想要当前的 TLS 和 ACME 行为,不要从默认 Ubuntu universe 随便装一个旧 Caddy。Caddy 项目文档里有 apt 源。安装后,caddy 用户存在,服务已启用。

bash
ssh root@YOUR_VPS_IP
apt update && apt -y install debian-keyring debian-archive-keyring apt-transport-https curl gpg

curl -1sLf 'https://dl.cloudsmith.io/public/caddy/stable/gpg.key' | gpg --dearmor -o /usr/share/keyrings/caddy-stable-archive-keyring.gpg
curl -1sLf 'https://dl.cloudsmith.io/public/caddy/stable/debian.deb.txt' | tee /etc/apt/sources.list.d/caddy-stable.list

apt update
apt -y install caddy

caddy version
systemctl status caddy --no-pager

步骤 2:第一份 Caddyfile——静态站点

默认 Caddyfile 是 /etc/caddy/Caddyfile。用你的域名替换它。如果主机名不是 localhost,配置一加载 Caddy 就会尝试拿证书。把站点文件放在 caddy 用户可读的目录(常见是 www-data 风格权限,但软件包使用用户 caddy)。

bash
mkdir -p /var/www/example
echo '<h1>It works</h1>' > /var/www/example/index.html
chown -R caddy:caddy /var/www/example

cat >/etc/caddy/Caddyfile <<'EOF'
example.com {
    root * /var/www/example
    file_server
    encode gzip
}
EOF

caddy validate --config /etc/caddy/Caddyfile
systemctl reload caddy

# Watch issuance:
journalctl -u caddy -f

步骤 3:反向代理本地应用

如果 Gunicorn、Node 或 Docker 监听 127.0.0.1:8000,Caddy 应该是唯一的公共进程。reverse_proxy 指令会以对大多数应用合理的方式转发 Host 和 X-Forwarded-* 头。如果应用生成绝对 HTTP URL,在应用里设置受信任代理 / HTTPS 标志(Django 的 SECURE_PROXY_SSL_HEADER、Express 的 trust proxy 等)。

bash
app.example.com {
    encode gzip
    reverse_proxy 127.0.0.1:8000
}

# Several hosts in one file are normal:
# blog.example.com {
#     root * /var/www/blog
#     file_server
# }

步骤 4:防火墙和 systemd

允许 80 和 443。Caddy 的单元是 caddy.service;如果进程健康,编辑 Caddyfile 后 reload 就够。如果为 DNS 插件更改环境变量,完整重启更清楚。证书默认在 /var/lib/caddy/.local/share/caddy/——如果你在意重装时的速率限制,把那条路径纳入备份。

bash
ufw allow OpenSSH
ufw allow 80/tcp
ufw allow 443/tcp
ufw enable

systemctl enable --now caddy
systemctl reload caddy

# Backup cert storage (path may vary slightly by version):
ls -la /var/lib/caddy/

步骤 5:日志、压缩和头

访问日志在机器人猛砸某条路径或你调试 404 时有帮助。可以按站点记录。如果托管浏览器应用,加上安全头;不要在不理解 HSTS 的情况下复制巨大的头包(一旦设置很长的 max-age,浏览器会记住)。

bash
example.com {
    root * /var/www/example
    file_server
    encode gzip
    log {
        output file /var/log/caddy/example.log
    }
    header {
        X-Content-Type-Options nosniff
        Referrer-Policy no-referrer-when-downgrade
        -Server
    }
}

mkdir -p /var/log/caddy
chown caddy:caddy /var/log/caddy
systemctl reload caddy

步骤 6:PHP 和其他附加功能

Caddy 可以用 php_fastcgi 指令与 PHP-FPM 对话。对许多 WordPress 或 Laravel 主机这就够了,但你仍然需要安装 php-fpm 以及匹配的套接字路径。如果你已经有完美的 Nginx PHP 配置,一个晚上迁完是可选的——Caddy 更擅长反向代理 + 静态 + 自动 TLS。

bash
example.com {
    root * /var/www/example
    php_fastcgi unix//run/php/php8.3-fpm.sock
    file_server
}

# Confirm FPM is running:
systemctl status php8.3-fpm

从 Nginx 迁移且没有停机意外

启动 Caddy 之前先停 Nginx,否则它们会抢 80/443。如果也在迁 IP,前一天降低 DNS TTL。用 curl --resolve 测试,这样你可以在切换 A 记录之前打到新 VPS。把 Nginx 配置在 git 里留一周,以防需要回滚。

  • systemctl stop nginx && systemctl disable nginx
  • 安装 Caddy,校验 Caddyfile,启动 Caddy
  • curl -I --resolve example.com:443:NEW_IP https://example.com
  • 仅当 IP 是新的时才改 DNS
  • 重新签发是自动的;不要同时对同一主机名跑 Certbot

故障排除

ACME 失败几乎总是 DNS、防火墙,或端口 80 上的另一个服务。Caddy 日志行会提到 tls.obtain。如果站点在 HTTP 上能用但 HTTPS 不行,签发从未完成。如果看到太多证书,你撞上了 Let's Encrypt 速率限制——测试时用 staging CA,不要用生产。

  • validate 失败:Caddyfile 语法,缺少大括号
  • root 上 permission denied:给站点目录 chown caddy
  • bind: address already in use — ss -tulpn | grep -E ':80|:443'
  • 证书超时:从 VPS 上 dig +short 该域名,ufw allow 80
  • 502 reverse_proxy:后端挂了,或你从容器网络错误地代理到 localhost

安全注意事项

Caddy 的 TLS 默认偏保守。你的工作是应用安全和 SSH。不要在公共接口上启用 Caddy 管理 API。默认管理端点是本地的;保持那样。如果使用网上的 Caddyfile,读每一个 matcher——把 /* 反向代理到内部 IP 的片段可以变成开放代理。

  • 不要暴露管理 API
  • 保持软件包更新
  • 只有在所有主机名的 HTTPS 都确认能用之后才上 HSTS
  • 分开测试和生产主机名以保护 ACME 速率限制

提示

  • caddy fmt --overwrite /etc/caddy/Caddyfile 让文件保持可读
  • 有很多相似站点时使用 import 片段
  • 对于 Docker,带挂载 Caddyfile 的 caddy:alpine 镜像很常见
  • 通配符证书需要 DNS 模块和 API 令牌——保护那个令牌
  • 重写整个文件之前先读 journalctl -u caddy

VPS 上的 Caddy 是:官方软件包、一份短 Caddyfile、打开的端口 80/443、已经指向服务器的 DNS,以及编辑后的 systemd reload。把它当静态文件服务器,或 Gunicorn、Node、Docker 前面的反向代理。当 ACME 能在端口 80 上应答时,自动 HTTPS 就会工作;如果签发失败,先修 DNS 和端口冲突,再怪 Caddy。如果你经常重装,备份 /var/lib/caddy。