Caddy 是一款用 Go 语言编写的快速、开源且注重安全性的 Web 服务器,是第一个使用 Let’s Encrypt 自动获取和更新 SSL/TLS 证书的网络服务器。Caddy 包含了 HTTP/2、QUIC 等现代功能特性。而且配置简洁,容易上手。

本文记录 Caddy 的基本用法,服务器环境是 Ubuntu 18.04。

安装 Caddy

Caddy 是模块化的,可以自由选择各种插件实现功能扩展。

  1. 访问官方下载网站 https://caddyserver.com/download
  2. 根据自己的需求,参考功能说明,选择扩展插件
  3. 复制安装脚本到服务器终端,执行安装。
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
sudo apt-get update
sudo apt-get upgrade

# 使用 personal 授权协议,添加 systemd service 插件
curl https://getcaddy.com | bash -s personal hook.service

# 将 Caddy 安装为 systemd 服务
sudo caddy -service install

# 另一种安装 systemd 服务的方法
curl -s https://.../caddy.service -o /etc/systemd/system/caddy.service  # or
wget https://raw.githubusercontent.com/.../caddy.service
sudo cp caddy.service /etc/systemd/system/

sudo chown root:root /etc/systemd/system/caddy.service
sudo chmod 644 /etc/systemd/system/caddy.service

sudo systemctl daemon-reload
sudo systemctl enable caddy.service

# 启动和管理 systemd 服务
sudo systemctl start caddy
sudo systemctl status caddy
sudo systemctl restart caddy
sudo systemctl reload caddy
sudo systemctl stop caddy

# 查看日志信息
journalctl -xe
journalctl -f -u caddy
journalctl --boot -u caddy

配置目录与权限

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
id www-data
groups www-data

# 创建 Web 用户、用户组
sudo groupadd -g 33 www-data
sudo useradd \
  -g www-data --no-user-group \
  --home-dir /var/www --no-create-home \
  --shell /usr/sbin/nologin \
  --system --uid 33 www-data

cat /etc/group | grep 33
cat /etc/passwd | grep 33

# 配置相关目录
sudo mkdir /etc/caddy
sudo mkdir /etc/ssl/caddy
sudo chown -R root:root /etc/caddy
sudo chown -R root:www-data /etc/ssl/caddy
sudo chmod 0770 /etc/ssl/caddy
1
2
3
4
5
# 不使用 root 运行 caddy,更安全
sudo chown www-data:www-data /usr/local/bin/caddy
sudo chmod 755 /usr/local/bin/caddy
# 允许caddy以非root用户身份绑定 80,443 特权端口
sudo setcap 'cap_net_bind_service=+ep' /usr/local/bin/caddy

使用 Caddy 部署网站

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
# 配置网站目录
sudo mkdir /var/www
sudo mkdir /var/log/caddy
sudo chown www-data:www-data /var/www
sudo chown www-data:www-data /var/log/caddy

# 网站服务测试
sudo mkdir -p /var/www/example.com
sudo echo "<h1>It Works!</h1>" > /var/www/example.com/index.html
sudo chown -R www-data:www-data /var/www/example.com
sudo chmod -R 555 /var/www/example.com

# 或:安装网站文件
sudo cp -R example.com /var/www/ # or
sudo mv example.com /var/www/

Caddyfile 配置文件

1
sudo vim /etc/caddy/Caddyfile
1
2
3
4
5
6
7
8
9
example.com {
  tls domain-admin@example.com
  root /var/www/example.com  # 网站根目录
  gzip
}

www.example.com {
  redir https://example.com{uri}
}
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
sudo chown root:root /etc/caddy/Caddyfile
sudo chmod 644 /etc/caddy/Caddyfile

# 检查配置文件
caddy -validate

# 重载配置文件
sudo systemctl reload caddy

# 确认服务可用
curl -I https://example.com

Caddy 与 Git 结合

1
2
3
4
5
6
7
example.com {
  internal /.git
  git https://github.com/markzhan/blog.git {
    hook /github_hook secret
    # interval 300
  }
}

Caddy 与 Hugo 结合

利用 Caddy 和 hugo、git 插件实现自动更新博客。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
example.com  {
  root /var/www/example.com

  log / /var/log/caddy/example.com_access.log "{combined}" {
    rotate_size 10  # Rotate a log when it reaches 100 MB
    rotate_age  14  # Keep rotated log files for 14 days
    rotate_keep 5   # Keep at most 10 rotated log files
    rotate_compress # Compress rotated log files in gzip format
  }

  errors /var/log/caddy/example.com_error.log {
    404 404.html # Not Found
    rotate_size 10  # Rotate a log when it reaches 100 MB
    rotate_age  14  # Keep rotated log files for 14 days
    rotate_keep 5   # Keep at most 10 rotated log files
    rotate_compress # Compress rotated log files in gzip format
  }

  cache {
    default_max_age 10m
  }

  proxy /webhook http://website:3000/webhook {
    transparent
  }

  git {
    # repo git@github.com:markzhan/blog.git
    repo https://github.com/markzhan/blog.git
    branch master
    path /home/user/blog/
    then hugo --source=/home/user/blog/ --destination=/var/www/example.com
    clone_args --recursive
    pull_args --recurse-submodules
    pull_args --allow-unrelated-histories
    # interval 60  # 间隔60秒, 或者使用钩子同步(推送更新)
    key /home/user/.ssh/id_rsa  # 私有仓库必须填写,并上传 id_rsa.pub
    hook /webhook ***  # hook地址和密钥,对应 GitHub 项目的 Payload URL 和 Secret
    hook_type github
  }
}

配置 Github 仓库的 WebHook

  • 打开 Github 仓库,点击 Settings,选择 Webhooks,点击 Add webhook
  • Payload URL 设置为网站根目录加 /webhook,例如 https://example.com/webhook
  • Content Type 选择 application/json
  • 设置 Secret
  • 事件可以只选择 Push Event, 点击 Add webhook 按钮即可。

Markdown 渲染

Caddy 可以直接把 md 文件渲染成网页:

1
2
3
4
5
6
example.com:80 {
  markdown {
    ext /data  # 不进行渲染的目录
    template [name] path  # 模板,不填使用默认
  }
}

文件下载服务

自带Web界面,还能在线编辑文件:

1
2
3
4
example.com:80 {
  root /home
  filemanager
}

关于证书

只要符合一些合理的条件,Caddy就会自动申请及配置SSL证书,为您的所有站点启用HTTPS:

  • 主机名:不为空; 不是localhost; 不是IP地址; 最多包含1个通配符(*); 通配符必须在最左边;
  • 端口不是明确的80; 方案不是明确的http; 未提供证书和密钥; 站点定义中未关闭TLS;
  • Caddy能够绑定到端口80和443(除非使用DNS验证)

不使用证书

1
2
3
4
example.com {
  tls off
  ...
}

使用自己申请的证书

手动从证书发行方申请证书,然后在Caddy配置中指定证书文件和秘钥对:

1
2
3
4
example.com {
  tls cert key
  ...
}

cert 是证书文件,key 是与证书文件匹配的服务器私钥文件。指定自己的证书和密钥将禁用自动HTTPS,包括更改端口和将HTTP重定向到HTTPS。如果你正在管理自己的证书,那这些需要你自己去做。

使用 CDN 机构提供的证书

too many registrations for this IP

证书授权机构对证书申请有限制。Let’s Encrypt 证书一周一个IP只能申请几次,如果因为某种原因重复申请证书达到上限,就会导致 IP 地址被封掉。IP 如果被封了,就要等一周再试。

证书存储失败可能导致重复申请。服务启动失败也可能导致重复申请。如果使用一键脚本申请证书,那么失败会自动再申请,很快就会被封IP。可以查看 Caddy 日志了解原因。

结束语

Caddy 以不同的方式实现 Nginx 的功能并尝试各种新的功能和特性。

参考

https://caddyserver.com/

https://caddyserver.com/docs

https://caddyserver.com/docs/placeholders

https://dengxiaolong.com/caddy/zh/

附录

通过Docker启动

https://hub.docker.com/r/abiosoft/caddy

1
2
3
4
5
6
7
8
9
docker run -d \
  --name caddy \
  --restart=always \
  -v /etc/ssl/caddy:/root/.caddy \
  -v /etc/caddy/Caddyfile:/etc/Caddyfile \
  -v /var/www/example.com:/srv/www/example.com \
  -v /var/log/caddy:/srv/log/caddy \
  -p 80:80 -p 443:443 \
  abiosoft/caddy

常用功能插件

插件 功能
http.filemanager 为指定目录提供一个文件管理界面
http.markdown 将Markdown文件作为HTML页面提供
http.hugo 提供了一个Web界面来管理Hugo网站
http.git 部署一个支持git push的站点。需要勾选 http.cors
http.cors 只允许指定域名的来源访问,只允许指定域名的跨域请求
http.cache 支持配置http缓存
http.expires 为正则表达式匹配的路径设置不同的过期时间
http.ratelimit 用于限制基于客户端IP地址的请求处理速率
http.ipfilter 基于客户端IP地址允许或阻止访问请求
http.geoip 通过IP地址确定用户的地理位置
http.realip 使logs和其他下游指令能够看到实际的客户端IP,而不是代理的IP
http.rewrite 允许客户端请求一个资源,但实际提供的是另一个资源(非HTTP重定向)
http.minify 动态压缩静态资源。支持CSS, HTML, JS, JSON, SVG和XML
http.upload 使用API或者HTTP方法POST/PUT完成上传文件
http.forwardproxy 允许Caddy服务器作为一个安全的Web代理。

补充

可用作中间件或独立应用程序的 Web文件浏览器

专注于HTTPS管理和反向代理的 SSLDocker