Caddy V2 介绍 ¶
Caddy 2 是一个强大的、企业级的、开源的 Web
服务器,具有用 Go
编写的自动 HTTPS
。也是当前唯一默认自动使用 TLS 的 Web 服务器。 使用 Caddy 2 轻松部署和扩展 HTTPS 。(静态文件、反向代理、负载平衡等)。
安装 Caddy ¶
apt 安装 caddy ¶
sudo apt install -y debian-keyring debian-archive-keyring apt-transport-https curl -1sLf 'https://dl.cloudsmith.io/public/caddy/stable/gpg.key' | sudo gpg --dearmor -o /usr/share/keyrings/caddy-stable-archive-keyring.gpg curl -1sLf 'https://dl.cloudsmith.io/public/caddy/stable/debian.deb.txt' | sudo tee /etc/apt/sources.list.d/caddy-stable.list sudo apt update sudo apt install caddy
ansible ¶
- hosts: caddy_huawei_shanghai
remote_user: root
tasks:
- name: Sync Caddyfile
copy:
src: caddy_huawei_shanghai/Caddyfile
dest: /etc/caddy/Caddyfile
- name: caddy add-package github.com/caddy-dns/dnspod
shell: "caddy list-modules|grep dnspod ; [ $? -eq 0 ] || (echo 不存在,正在安装 ; caddy add-package github.com/caddy-dns/dnspod ; systemctl restart caddy)"
- name: Reload
shell:
chdir: /etc/caddy
cmd: caddy reload
docker compose 方式管理 ¶
1. 创建工作目录 ¶
mkdir /root/code/Caddy/
2. 编写 compose 文件 ¶
/root/code/Caddy/compose.yaml
services:
caddy:
image: swr.cn-east-3.myhuaweicloud.com/china/caddy:2.7.5
# image: caddy:<version>
restart: unless-stopped
ports:
- "80:80"
- "443:443"
- "443:443/udp"
volumes:
- ./caddy:/etc/caddy/
- ./site:/srv
- ./caddy_data:/data
- ./caddy_config:/config
Note
数据目录不能被视为缓存。它的内容不是短暂的,也不是仅仅为了表演。Caddy 将 TLS 证书、私钥、OCSP 订书钉和其他必要信息存储到数据目录中。如果不了解其含义,则不应将其清除。
3. 编写 alias 快捷命令 ¶
/root/code/Caddy/compose.yaml
# caddy 相关
caddy_dir="/root/code/Caddy/"
alias caddy-edit='vim ${caddy_dir}caddy/Caddyfile'
alias caddy-reload='docker compose -f ${caddy_dir}compose.yaml exec caddy /bin/sh -c "caddy fmt --overwrite /etc/caddy/Caddyfile && caddy reload -c /etc/caddy/Caddyfile"'
source ~/.zshrc
编写 Caddyfile 文件 ¶
官网:V1 与 V2 区别
https://caddyserver.com/docs/v2-upgrade
caddy-edit
打印 log 日志 ¶
# 打印错误日志
{
log {
# Write logs to a file (with log rolling, which is enabled by default):
output file /var/log/caddy/access.log
level ERROR
}
}
静态文件、后端负载均衡 ¶
linuxnbg.com {
encode gzip
root * /code/linuxnbg/dm-blog/public
file_server
reverse_proxy /api/* {
to localhost:9000 localhost:3000
lb_policy round_robin
}
}
端口监听 文件 并反向代理 ¶
:7777 {
encode gzip
root * /code/linuxnbg/dm-blog/public
file_server
}
linuxnbg.com {
reverse_proxy <host>:7000
}
重定向至 其他域名 例如百度 ¶
baidu.linuxnbg.com {
redir https://www.baidu.com
}
将 linuxnbg.com 重定向至 www.linuxnbg.com ¶
linuxnbg.com {
redir https://www.linuxnbg.com
}
www.linuxnbg.com {
root * /code/linuxnbg/dm-blog/public
file_server
}
将 www.linuxnbg.com 重定向至 linuxnbg.com ¶
www.linuxnbg.com {
redir https://linuxnbg.com
}
linuxnbg.com {
root * /code/linuxnbg/dm-blog/public
file_server
}
负载均衡示例 ¶
linuxnbg.com {
reverse_proxy {
to localhost:9000 localhost:3000
lb_policy round_robin
}
}
# lb_policy 参数
first:选取第一个可用的上游
random:随机选取一个可用的上游
least_conn:选取当前请求数最少的上游,这个比较适合长连接的场景
ip_hash:根据IP的Hash值选取一个固定的上游
random_choose :随机选取2个或者更多个上游,然后再从中选择负载最小的,n通常为2
header:这个是根据请求头的Hash选取一个固定的上游,和 ip_hash 很像,只不过它是根据指定的请求头的值进行Hash,然后选取上游的。所以这里的用法是 header <request_header_name> ,要指定一个请求头。
uri_hash:这个也和 ip_hash 很像,只不过它是根据请求的URI进行Hash,然后选取一个上游。
round_robin:这个策略是循环迭代,挨个使用一个个上游,每个上游都可以被用到,轮着来。
cookie [ []] :如果你理解了以上几个基于Hash的负载均衡策略,那么这个 cookie 的也会很好理解,其实它就是通过cookie的值的hash来选取一个上游。在这里 name 表示要获取cookie值的 name ,默认是 lb , secret 是用于Hash的密钥,使用的是Hamc256算法
dnspod ¶
- 安装 dnspod
caddy list-modules|grep dnspod ; [ $? -eq 0 ] || (echo 不存在,正在安装 ; caddy add-package github.com/caddy-dns/dnspod ; systemctl restart caddy)
- 使用 dnspod
# 定义
(dnspod) {
tls {
dns dnspod <,>
# solvers mosca.dnspod.net # 腾讯云、dnspod 升级后、需要手动指定
resolvers SHELF.DNSPOD.NET
}
}
*.linuxnbg.com {
import dnspod
@docs host docs.linuxnbg.com
handle @docs {
reverse_proxy 10.0.16.12:8000
}
@gitea host gitea.linuxnbg.com
handle @gitea {
reverse_proxy 10.0.16.12:3000
}
@jenkins host jenkins.linuxnbg.com
handle @jenkins {
reverse_proxy 10.0.16.12:9000
}
}
linuxnbg.com:90 {
import dnspod
handle {
reverse_proxy 192.168.0.218:9999
}
}
华为云 obs 静态建站 ¶
2020.linuxnbg.com {
reverse_proxy linuxnbg.obs.cn-north-9.myhuaweicloud.com {
header_up Host {upstream_hostport}
}
header -content-disposition # 去掉下载参数
rewrite / /2020/index.html
uri replace /js/ /2020/js/
uri replace /css/ /2020/css/
}
Caddy的简单认证 ¶
生成 hash-password 字符串 ¶
将生成的字符串贴在 Caddyfile 的 basicauth 块中。
caddy hash-password
Caddyfile 编写 ¶
one.example.com {
basicauth / {
user hashed-password
}
reverse_proxy service1:8001
}
two.example.com {
basicauth / {
user hashed-password
}
reverse_proxy service2:8002
}
three.example.com {
basicauth / {
user hashed-password
}
reverse_proxy service3:8003
}
Caddy 重用配置块 ¶
Caddy 还支持“snippets”,您可以在其他地方“导入”的可重用配置块,所以让我们稍微清理一下基本身份验证。这个和上面基本一样,但是现在用户和密码只在一个地方,更容易管理。
(basic-auth) {
basicauth / {
user hashed-password
}
}
one.example.com {
import basic-auth
reverse_proxy service1:8001
}
two.example.com {
import basic-auth
reverse_proxy service2:8002
}
three.example.com {
import basic-auth
reverse_proxy service3:8003
}
因为我们仍然需要为每项服务分别进行身份验证。如果只有某种方式可以登录一次,并让 Caddy 为每项服务识别一次身份验证
(basic-auth) {
basicauth / {
user hashed-password
}
}
# a snippet to check if a cookie token is set. if not, store the current page as the referer and redirect to auth site
(proxy-auth) {
# if cookie not = some-token-nonsense
@no-auth {
not header_regexp mycookie Cookie myid=<regex-to-match-id>
# https://github.com/caddyserver/caddy/issues/3916
}
# store current time, page and redirect to auth
route @no-auth {
header Set-Cookie "myreferer={scheme}://{host}{uri}; Domain=example.com; Path=/; Max-Age=30; HttpOnly; SameSite=Strict; Secure"
redir https://auth.example.com
}
}
# a pseudo site that only requires basic auth, sets cookie, and redirects back to original site
auth.example.com {
route / {
# require authentication
import basic-auth
# upon successful auth, set a client token
header Set-Cookie "myid=some-long-hopefully-random-string; Domain=example.com; Path=/; Max-Age=3600; HttpOnly; SameSite=Strict; Secure"
#delete the referer cookie
header +Set-Cookie "myreferer=null; Domain=example.com; Path=/; Expires=Thu, 25 Sep 1971 12:00:00 GMT; HttpOnly; SameSite=Strict; Secure"
# redirect back to the original site
redir {http.request.cookie.myreferer}
}
# fallback
respond "Hi."
}
one.example.com {
import proxy-auth
reverse_proxy service1:8001
}
two.example.com {
import proxy-auth
reverse_proxy service2:8002
}
three.example.com {
import proxy-auth
reverse_proxy service3:8003
}