当你发布网站或将应用程序置于反向代理之后时,配置 HTTPS 可能比安装 Web 服务器更耗时。对于大多数部署场景,Caddy 会自动处理证书签发、续期以及 HTTP 到 HTTPS 的重定向。

一旦你的域名指向服务器,一个简短的 Caddyfile 通常就足以通过 HTTP/2 和 HTTP/3 提供站点服务。本指南将介绍如何在 Ubuntu 26.04 上从官方 APT 仓库安装 Caddy、托管静态站点、配置反向代理,以及使用 systemd 管理服务。

快速参考

任务命令
安装 Caddysudo apt install caddy
编辑配置sudo nano /etc/caddy/Caddyfile
重载配置sudo systemctl reload caddy
重启 Caddysudo systemctl restart caddy
检查状态sudo systemctl status caddy
验证 Caddyfilesudo caddy validate --config /etc/caddy/Caddyfile
格式化 Caddyfilesudo caddy fmt --overwrite /etc/caddy/Caddyfile
查看日志sudo journalctl -u caddy -f

前提条件

开始之前,请确保你具备:

  • 一台 Ubuntu 26.04 服务器,并拥有具有 sudo 权限的用户。
  • 如果你需要公开受信任的 HTTPS 证书,域名需配置指向该服务器的 A 或 AAAA 记录。
  • 在服务器防火墙和任何提供商级别的防火墙中开放 TCP 端口 80 和 443。

如果你使用 UFW,请使用以下命令允许 HTTP 和 HTTPS 流量:

终端
sudo ufw allow 80/tcp
sudo ufw allow 443/tcp

Caddy 支持基于 UDP 的 HTTP/3。如果你希望客户端使用它,请允许 UDP 端口 443:

终端
sudo ufw allow 443/udp

如果你只想在本地测试 Caddy,请在 Caddyfile 中使用显式的 HTTP 地址(例如 http://localhost)或非标准端口(例如 :8080)。Caddy 不会为该站点地址启用自动 HTTPS。

从官方仓库安装 Caddy

Caddy 项目在 Cloudsmith 上维护着官方 APT 仓库。我们将使用它来安装当前稳定版本,并通过 APT 接收未来的 Caddy 更新。

安装前置依赖包:

终端
sudo apt update
sudo apt install -y debian-keyring debian-archive-keyring apt-transport-https curl

添加 Caddy 签名密钥:

终端
curl -1sLf 'https://dl.cloudsmith.io/public/caddy/stable/gpg.key' \
  | sudo gpg --dearmor -o /usr/share/keyrings/caddy-stable-archive-keyring.gpg

添加 Caddy APT 仓库:

终端
curl -1sLf 'https://dl.cloudsmith.io/public/caddy/stable/debian.deb.txt' \
  | sudo tee /etc/apt/sources.list.d/caddy-stable.list

使两个仓库文件对 APT 可读:

终端
sudo chmod o+r /usr/share/keyrings/caddy-stable-archive-keyring.gpg
sudo chmod o+r /etc/apt/sources.list.d/caddy-stable.list

更新软件包索引并安装 Caddy:

终端
sudo apt update
sudo apt install -y caddy

该软件包会将二进制文件安装到 /usr/bin/caddy,创建 caddy 系统用户,在 /etc/caddy/Caddyfile 添加默认配置,并安装 caddy.service systemd 单元。

显示已安装的版本:

终端
caddy version

接下来,确认服务正在运行:

终端
sudo systemctl status caddy

状态输出应显示 active (running)。按 q 退出状态界面。

你也可以从服务器请求默认站点:

终端
curl -I http://localhost

正常工作的安装会返回 HTTP 200 OK 响应,并在响应头中包含 Server: Caddy。你也可以在浏览器中打开服务器的 IP 地址来查看默认页面。

托管静态站点

Caddy 从 /etc/caddy/Caddyfile 读取配置。默认文件在端口 80 上提供来自 /usr/share/caddy 的内容。

在修改之前,先创建备份:

终端
sudo cp /etc/caddy/Caddyfile /etc/caddy/Caddyfile.backup

接下来,打开 Caddyfile:

终端
sudo nano /etc/caddy/Caddyfile

将内容替换为以下站点块。将 example.com 更改为你的域名:

/etc/caddy/Caddyfilecaddy
example.com {
    root * /var/www/example.com
    file_server
}

第一行的域名是站点地址。Caddy 使用它来获取证书、将 HTTP 请求重定向到 HTTPS,并安全地提供站点服务。你不需要单独的证书块或 listen 指令。

创建文档根目录并添加测试页面:

终端
sudo mkdir -p /var/www/example.com
echo "<h1>Hello from Caddy</h1>" | sudo tee /var/www/example.com/index.html
sudo chmod -R a+rX /var/www/example.com

caddy 服务只需要对静态站点文件的读取权限。将文件所有权保留给你的部署用户或 root 可以防止 Web 服务器进程修改它们。

在应用新配置之前,先验证它:

终端
sudo caddy validate --config /etc/caddy/Caddyfile

如果命令没有报告错误,请重载 Caddy:

终端
sudo systemctl reload caddy

重载命令会在不停止服务的情况下应用新的 Caddyfile。然后 Caddy 会请求证书并将 HTTP 流量重定向到 HTTPS。如果 DNS 指向服务器且端口 80 和 443 可达,证书签发通常会在几秒内完成。

添加反向代理

Caddy 常用于运行在同一服务器上的应用程序前端。例如,如果一个 Node.js 或 Python 应用程序监听 127.0.0.1:3000,请使用以下 Caddyfile:

/etc/caddy/Caddyfilecaddy
app.example.com {
    reverse_proxy 127.0.0.1:3000
}

使用此配置,Caddy 会处理 HTTPS 并将请求转发到应用程序。它还会传递传入的 Host 头,设置常见的 X-Forwarded-* 头,并且无需额外指令即可支持 WebSocket 连接。

要代理子路径,请限定指令的作用域:

/etc/caddy/Caddyfilecaddy
example.com {
    root * /var/www/example.com
    file_server

    handle /api/* {
        reverse_proxy 127.0.0.1:3000
    }
}

/api/ 下的请求会以不变的 /api 前缀发送到应用程序。其他请求继续使用静态文件服务器。如果应用程序期望的是 /users 而不是 /api/users,请将 handle 替换为 handle_path,以便在代理请求之前移除匹配的前缀。

修改后验证并重载配置:

终端
sudo caddy validate --config /etc/caddy/Caddyfile
sudo systemctl reload caddy

如果你也使用 Nginx,请参阅我们的 Nginx 反向代理指南了解等效配置。

托管多个站点

你可以在同一个 Caddyfile 中托管多个域名和子域名。为每个主机名添加一个站点块:

/etc/caddy/Caddyfilecaddy
example.com {
    root * /var/www/example.com
    file_server
}

blog.example.com {
    root * /var/www/blog
    file_server
    encode gzip
}

api.example.com {
    reverse_proxy 127.0.0.1:8080
}

Caddy 会为每个符合条件的主机名获取并续期证书。与 Nginx 的 sites-available 设置不同,此配置不需要单独的符号链接步骤。

随着站点数量的增长,你可以使用 import 指令将配置拆分到多个文件中:

/etc/caddy/Caddyfilecaddy
import /etc/caddy/sites/*.caddy

创建 /etc/caddy/sites 目录,然后为每个站点添加一个 .caddy 文件。添加或删除导入的文件后,请运行 caddy validate。

验证和格式化 Caddyfile

在每次重载之前,请验证 Caddyfile:

终端
sudo caddy validate --config /etc/caddy/Caddyfile

验证会解析文件并配置其模块,而不会启动另一个服务器。如果 Caddy 发现语法或配置错误,它会报告受影响的行或指令。

Caddy 还包含一个用于缩进和空格的格式化工具:

终端
sudo caddy fmt --overwrite /etc/caddy/Caddyfile

--overwrite 选项会用格式化后的版本替换文件。如果你想在部署前检查格式更改,请查看文件或将其保留在版本控制中。

使用 systemd 管理 Caddy

该软件包将 Caddy 作为名为 caddy.service 的 systemd 服务运行。使用以下命令来控制它:

sudo systemctl start caddy
sudo systemctl stop caddy
sudo systemctl restart caddy
sudo systemctl reload caddy
sudo systemctl status caddy

对于 Caddyfile 的更改,请使用 reload 而不是 restart。重载通过 Caddy 的 admin API 应用新配置,而不会中断活动连接。

该软件包通常在安装期间启用服务。如果服务被禁用,请使用以下命令重新启用:

sudo systemctl enable caddy

查看 Caddy 日志

Caddy 将其运行时和服务日志写入 systemd journal。使用 journalctl 跟踪新日志条目:

sudo journalctl -u caddy -f

访问日志是独立的,默认情况下未启用。要将 JSON 访问日志写入文件,请在站点块中添加 log 指令:

/etc/caddy/Caddyfilecaddy
example.com {
    root * /var/www/example.com
    file_server

    log {
        output file /var/log/caddy/access.log
        format json
    }
}

使用正确的所有权创建一次日志目录:

sudo mkdir -p /var/log/caddy
sudo chown caddy:caddy /var/log/caddy

验证更改后重载 Caddy。Caddy 默认轮换基于文件的访问日志,JSON 输出可以被 Vector、Loki 或 Elasticsearch 等日志收集工具读取。

更新 Caddy

由于 Caddy 是从 APT 仓库安装的,你可以使用常规的软件包工作流进行更新:

sudo apt update
sudo apt install --only-upgrade caddy

软件包升级会保留你的 Caddyfile 和 /var/lib/caddy 下的 Caddy 数据。更新后,确认已安装的版本和服务状态:

caddy version
sudo systemctl status caddy

故障排除

端口 80 或 443 上出现 bind: address already in use
另一个 Web 服务器(通常是 Apache 或之前安装的 Nginx)已经在监听该端口。使用 sudo systemctl stop apache2 或 sudo systemctl stop nginx 停止冲突的服务,然后启动 Caddy。

证书签发失败
Caddy 需要端口 80 的入站访问用于 HTTP 质询,或端口 443 用于 TLS-ALPN 质询。确认防火墙允许这两个端口,每个配置的 A 或 AAAA 记录都指向此服务器,并且没有其他代理拦截验证请求。journal 日志(journalctl -u caddy)会显示确切的 ACME 错误。

读取 /var/www/... 时出现 permission denied
Caddy 以 caddy 用户身份运行,而不是 root。文档根目录下的文件必须可读,父目录必须可执行。运行 sudo chmod -R a+rX /var/www/example.com,如果错误仍然存在,请检查每个父目录。避免将仅需要提供的文件的所有权授予服务账户。

Caddyfile 验证通过但站点无法访问
检查站点块是否使用了浏览器请求的确切主机名。使用 getent hosts example.com 测试 DNS,然后使用 curl -v https://example.com 检查连接和响应。

HTTP 请求未重定向到 HTTPS
当站点地址以 http:// 开头或仅包含 HTTP 端口时,自动 HTTPS 将被禁用。在 Caddyfile 中使用 example.com 而不是 http://example.com,验证配置,并检查 journal 中的证书错误。