Caddy部署与使用—踩坑总结

Caddy部署与使用

官方文档

https://github.com/caddyserver/caddy

Caddy是什么

相信大家都知道apache、nginx,那么caddy也一样,它是一个Web服务器,可以帮你托管你的Web服务,让其他人可以通过互联网访问。

比如你想搭建一个博客,可以在互联网上被其他人访问,那么就可以使用caddy,相比nginx来说,它配置更简单。

对于caddy,官方是这么定义的:

Caddy 2 is a powerful, enterprise-ready, open source web server with automatic HTTPS written in Go

Caddy是一个强大的、企业级的、开放源代码的web服务器,使用Go编写,并且可以自动HTTPS加密(其实就是自动配置TLS证书并管理)。

安装Caddy
得益于Go语言,caddy是一个独立的二进制包,所以它没有任何依赖,你可以直接从官网下载并安装它。

docker-compose部署caddy并开启https请求

创建目录(在root目录下)

$ mkdir -p caddy/{conf,logs,www}
$ cd caddy

配置Caddyfile

$ vi conf/Caddyfile
www.?????.net {
  gzip
  root /opt/www 
  timeouts 30s
  log /opt/logs/access.log
  proxy / localhost:8080  #根url 直接代理转发
  proxy /more localhost:8081 localhost:8082  #负载均衡
}

我自己的配置
image-20220820203728669

我想直接访问 www.???.net 就帮我代理转发到 localhost:8080,可以!我想直接访问 www.???.net 就帮我代理转发到 localhost:8080,可以!

以上是在配置公网域名后的配置,还没有配置域名?那直接用 IP 就行,如下
192.168.1.2:80 192.168.1.2:443 {
  gzip
  root /opt/www 
  tls self_signed  #自动签名,很重要
  timeouts 30s
  log /opt/logs/access.log
  proxy /other localhost:8080
}

自己看着修改

配置docker-compose.yml

$ vi docker-compose.yml

version: '3.7'

services:
  # http/2 server
  caddy:
    image: abiosoft/caddy
    container_name: caddy
    hostname: caddy
    domainname: caddy
    restart: always
    environment:
      - ACME_AGREE=true
      - TZ=Asia/Shanghai
      - agree
    volumes:
      - "/caddy/conf/Caddyfile:/etc/Caddyfile"
      - "/caddy/.caddy:/root/.caddy"
      - "/caddy/logs:/opt/logs"
      - "/caddy/www:/opt/www"
    ports:
      - "80:80"
      - "443:443"
      - "443:443/udp"

image-20220820204046620

其中三个环境变量(environment)非常重要

1、配置上海时区
2、同意caddy自动配置ssl证书
3、caddy需要的反馈邮箱

启动

$ docker-compose up -d
$ docker logs -f caddy    # 查看日志

测试

随便复制个文件到 www 目录下,我复制了个图片bg.jpg,
然后输入 https://192.168.1.2/bg.jpg

image-20220820204858762

Caddyfile配置详解

Caddyfile 主要包含一些通用的配置,并将其抽到配置片段中,类似于 nginx 的 nginx.conf 主配置;在最后部分通过 import 关键字引入其他具体站点配置,类似 nginx 的 vhost 配置。

# 授权认证服务
http://auth-server.jianpeicn.com {
  reverse_proxy http://172.16.95.146:5000
}


# 基础服务
http://management-server.jianpeicn.com {
  reverse_proxy /api/identity/*               http://172.16.95.146:5001
  reverse_proxy /api/multi-tenancy/*          http://172.16.95.146:5003
  reverse_proxy /api/identity-server/*        http://172.16.95.146:5002
  reverse_proxy /api/permission-management/*  http://172.16.95.146:5004
  reverse_proxy /api/storage/*                http://120.26.112.192:7020
  reverse_proxy /*                            http://172.16.95.146:7000
}

https://management-server.jianpeicn.com {
  tls internal
  reverse_proxy /api/identity/*               http://172.16.95.146:5001
  reverse_proxy /api/multi-tenancy/*          http://172.16.95.146:5003
  reverse_proxy /api/identity-server/*        http://172.16.95.146:5002
  reverse_proxy /api/permission-management/*  http://172.16.95.146:5004
  reverse_proxy /api/storage/*                http://120.26.112.192:7020
  reverse_proxy /*                            http://172.16.95.146:7000
}
  • tls: 是否使用htpps证书(内网使用internal,外网使用邮箱)
  • reverse_proxy: 代理地址

配置片段

Caddyfile 支持类似代码中 function 一样的配置片段,这些配置片段可以在任意位置被 import,同时可以接受参数,以下为配置片断示例:

# 括号内为片段名称,可以自行定义
(TLS) {
    protocols tls1.2 tls1.3
    ciphers TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256 TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256 TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384 TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384 TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256 TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256
}
 
# 在任意位置可以引用此片段从而达到配置复用
import TLS

配置模块化

import 指令除了支持引用配置片段以外,还支持引用外部文件,同时支持通配符,有了这个命令以后我们就可以方便的将配置文件进行模块化处理:

# 引用外部的 /etc/caddy/*.caddy
import /etc/caddy/*.caddy

站点配置

针对于站点域名配置,Caddyfile 比较自由化,其格式如下:

地址 {
    站点配置
}

关于这个 “地址” 接受多种格式,以下都为合法的地址格式:

localhost

example.com

:443

http://example.com
localhost:8080

127.0.0.1

[::1]:2015

example.com/foo/*

*.example.com

http://

配置多个Web服务

既然caddy是一个Web服务器,那么就不止可以托管一个Web站点,如果需要托管多个,怎么做呢?

localhost {
    respond "Hello, world!"
}
localhost:2016 {
    respond "Goodbye, world!"
}

配置反向代理

localhost
reverse_proxy 127.0.0.1:9000

以上示例,都是把https://localhost/ 的请求代理到127.0.0.1:9000 。

以上http默认的是80端口,https默认的是443端口。当然,我们也可以换个端口,比如2016.

:2016
reverse_proxy 127.0.0.1:9000

代理匹配的请求

caddy作为一个强大的web服务器,其反向打理功能肯定不止以上这么简单。比如,我们不想代理全部的网络请求,而是只想代理匹配的怎么做呢?比如代理 /api 这个Path下的。

reverse_proxy /api/*  {
    to 127.0.0.1:9000
}

从以上示例可以看到,只需要在 reverse_proxy 指令后,加 /api/* 这个match即可,这和Nginx的 location 是非常相似的。

代理到多个上游服务

为了高可用,上游服务我们会部署多少,这样当一个有问题的时候,不会影响产品功能。下面我们看下Caddy是如何实现这一能力的。

reverse_proxy node1:80 node2:80 node3:80

这样就会所有的请求,随机的反向代理到这三个node节点上了。
当然我们还可以这样配置:

reverse_proxy /api/*  {
    to node1:80 node2:80 node3:80
}

当同时配置多个反向代理服务的时候,就有了负载均衡了。以上默认的情况下,是随机的,也就是caddy会随机的选择一个上游服务使用。

Caddy的负载均衡

只要定义了多个上游(upstream),Caddy的反向代理就会使用负载均衡的能力,,就是用了负载均衡,代码如下所示:

reverse_proxy /api/*  {
    to node1:80 node2:80 node3:80
}

以上这个配置,它的负载均衡策略(调度方式)默认是随机的,我们可以通过 lb_policy 来指定不同的负载均衡策略,比如

reverse_proxy /api/*  {
    to node1:80 node2:80 node3:80
    lb_policy first
}

以上代码指定的是 first 的负责均衡策略,也就是选择第一个可用的上游。

负载均衡策略

除了 first 外,还有很多负载均衡策略以供我们选择,下面就为你分别介绍他们。

1- first:选取第一个可用的上游

2- random:随机选取一个可用的上游

3- least_conn:选取当前请求数最少的上游,这个比较适合长连接的场景

4- ip_hash:根据IP的Hash值选取一个固定的上游

5- random_choose 

:随机选取2个或者更多个上游,然后再从中选择负载最小的,n通常为2
6- header:这个是根据请求头的Hash选取一个固定的上游,和 ip_hash 很像,只不过它是根据指定的请求头的值进行Hash,然后选取上游的。所以这里的用法是 header ,要指定一个请求头。

7- uri_hash:这个也和 ip_hash 很像,只不过它是根据请求的URI进行Hash,然后选取一个上游。

8- round_robin:这个策略是循环迭代,挨个使用一个个上游,每个上游都可以被用到,轮着来。

9- cookie 

重试等待时间

当你设置了多个上游主机,启用了负载均衡后,不可避免的会遇到上游服务不可用的情况,默认情况下,Caddy的处理是:当上游服务器不可用的时候,客户端的请求就没有可用的服务来相应,客户端就会报错。

当然除了立即响应服务不可用,Caddy还提供了负责均衡的重试功能,这就是 lb_try_duration ,他可以设置一个重试的时间,比如1000毫秒。

这是什么意思呢?如果你设置了lb_try_duration 为1000毫秒,那么Caddy的负载均衡在处理该客户端请求时,如果选用了一个不可用的上游服务,就会继续重试,一直到找到一个可用的上游或者到了设置的1000毫秒时间为止。

也就是,这个时间,就是Caddy的负载平衡器尝试查找可用的上游主机时,客户端将等待最长时间

重试时间间隔

有了重试等待时间,肯定也有重试时间间隔,因为正常的逻辑上来讲,不能马上去重试,因为马上重试的话,很大概率拿到的也是个不可用的上游主机,所以需要一个重试时间间隔,来控制重试的节奏,在Caddy中,就是 lb_try_interval ,默认是重试间隔是250ms,250毫秒。

所以你可以看到, lb_try_interval 是结合着lb_try_duration 来使用的。lb_try_duration 是重试等待的总时间,而lb_try_interval 是在这段时间内,每隔多久重试一次。

负载均衡示例非常简单,按照配置写即可

# 按照ip hash 负载均衡
reverse_proxy /api/*  {
    to node1:80 node2:80 node3:80
    lb_policy ip_hash
}

设置等待时间的话,可以这样:

# 按照ip hash 负载均衡,重试等待时间为5秒
reverse_proxy /api/*  {
    to node1:80 node2:80 node3:80
    lb_policy ip_hash
    lb_try_duration 5s
}

环境变量

Caddyfile 支持直接引用系统环境变量,通过此功能可以将一些敏感信息从配置文件中剔除:

# 引用环境变量 GANDI_API_TOKEN
dns gandi {$GANDI_API_TOKEN}

配置片段参数支持

针对于配置片段,Caddyfile 还支持类似于函数代码的参数支持,通过参数支持可以让外部引用时动态修改配置信息:

(LOG) {
    log {
        format json  {
            time_format "iso8601"
        }
        # "{args.0}" 引用传入的第一个参数,此处用于动态传入日志文件名称
        output file "{args.0}" {
            roll_size 100mb
            roll_keep 3
            roll_keep_for 7d
        }
    }
}
 
# 引用片段
import LOG "/data/logs/mritd.com.log"

自动证书申请

在启动 Caddy2 之前,如果目标域名(例如: www.example.com)已经解析到了本机,那么 Caddy2 启动后会尝试自动通过 ACME HTTP 挑战申请证书;如果期望使用 DNS 的方式申请证书则需要其他 DNS 插件支持,比如上面编译的 --with github.com/caddy-dns/gandi 为 gandi 服务商的 DNS 插件;关于使用 DNS 挑战的配置编写方式需要具体去看其插件文档,目前 gandi 的配置如下:

tls {
 dns gandi {env.GANDI_API_TOKEN}
}

配置完成后 Caddy2 会通过 ACME DNS 挑战申请证书,值得注意的是即使通过 DNS 申请证书默认也不会申请泛域名证书,如果想要调整这种细节配置请使用 json 配置或管理 API。

(LOG) {
    log {
        # 日志格式参考 https://github.com/caddyserver/format-encoder 插件文档
        format formatted "[{ts}] {request>remote_addr} {request>proto} {request>method} <- {status} -> {request>host} {request>uri} {request>headers>User-Agent>[0]}"  {
            time_format "iso8601"
        }
        output file "{args.0}" {
            roll_size 100mb
            roll_keep 3
            roll_keep_for 7d
        }
    }
}
 
(TLS) {
    # TLS 配置采用 https://mozilla.github.io/server-side-tls/ssl-config-generator/ 生成,SSL Labs 评分 A+
    protocols tls1.2 tls1.3
    ciphers TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256 TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256 TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384 TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384 TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256 TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256
}
 
(HSTS) {
    # HSTS (63072000 seconds)
    header / Strict-Transport-Security "max-age=63072000"
}
 
(ACME_GANDI) {
    # 从环境变量获取 GANDI_API_TOKEN
    dns gandi {$GANDI_API_TOKEN}
}
 
# 聚合上面的配置片段为新的片段
(COMMON_CONFIG) {
    # 压缩支持
    encode zstd gzip
 
    # TLS 配置
    tls {
        import TLS
        import ACME_GANDI
    }
 
    # HSTS
    import HSTS
}
 
# 开启 HTTP3 实验性支持
{
    servers :443 {
        protocol {
            experimental_http3
        }
    }
}
 
# 引入其他具体的站点配置
import /etc/caddy/*.caddy
mritd.com.caddy

mritd.com.caddy 为主站点配置,主站点配置内主要编写一些路由规则,TLS 等都从配置片段引入,这样可以保持统一。

www.mritd.com {
    # 重定向到 mritd.com(默认 302)
    redir https://mritd.com{uri}
 
    # 日志
    import LOG "/data/logs/mritd.com.log"
 
    # TLS、HSTS、ACME 等通用配置
    import COMMON_CONFIG
}
 
mritd.com {
    # 路由
    route /* {
        reverse_proxy mritd_com:80
    }
    # 日志
    import LOG "/data/logs/mritd.com.log"
    # TLS、HSTS、ACME 等通用配置
    import COMMON_CONFIG
}
mritd.me.caddy

mritd.me.caddy 为老站点配置,目前主要将其 301 到新站点即可。

www.mritd.me {
    # 重定向到 mritd.com
    # 最后的 "code" 支持三种参数
    # temporary => 302
    # permanent => 301
    # html => HTML document redirect
    redir https://mritd.com{uri} permanent
 
    # 日志
    import LOG "/data/logs/mritd.com.log"
 
    # TLS、HSTS、ACME 等通用配置
    import COMMON_CONFIG
}
 
mritd.me {
    # 重定向
    redir https://mritd.com{uri} permanent
 
    # 日志
    import LOG "/data/logs/mritd.com.log"
 
    # TLS、HSTS、ACME 等通用配置
    import COMMON_CONFIG
}
采用以下大佬文章理解caddy这个服务
www.mritd.me {
    # 重定向到 mritd.com
    # 最后的 "code" 支持三种参数
    # temporary => 302
    # permanent => 301
    # html => HTML document redirect
    redir https://mritd.com{uri} permanent
 
    # 日志
    import LOG "/data/logs/mritd.com.log"
 
    # TLS、HSTS、ACME 等通用配置
    import COMMON_CONFIG
}
 
mritd.me {
    # 重定向
    redir https://mritd.com{uri} permanent
 
    # 日志
    import LOG "/data/logs/mritd.com.log"
 
    # TLS、HSTS、ACME 等通用配置
    import COMMON_CONFIG
}
采用以下大佬文章理解caddy这个服务

image-20220820211704958

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值