前言:Caddy是什么

Caddy是一个内置了https证书申请的模块化的Web服务器。Caddy配置也相当简洁,利用Caddy可以快速简单地完成https证书的申请和部署内网的服务。如果你是有公网80端口,那么可以使用HTTP-01 challenge完成域名所有权完成证书申请,但大多数场景(比如部署在内网的服务)没有公网80端口,那就只能使用DNS-01 challenge了,这个要求配合DNS托管商的API来完成,Caddy默认是不集成DNS供应商API的,需要自己编译,因此为了方便使用,我就直接写了个Docker,不用每次用都编译了。顺带贴一些可能用得上的简单示例配置(包括申请Google CA、静态文件服务、反向代理等),希望能帮助到大家快速简单上手Caddy。

caddy docker

Github项目地址: https://github.com/kkkgo/caddy-docker
docker pull sliamb/caddy
pull size
Docker Platforms
一个caddy的docker镜像,集成编译dns providers插件,Actions自动编译更新。
包括以下插件:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
--with github.com/caddy-dns/cloudflare 
--with github.com/caddy-dns/dnspod 
--with github.com/caddy-dns/alidns 
--with github.com/caddy-dns/acmedns 
--with github.com/caddy-dns/godaddy 
--with github.com/caddy-dns/digitalocean 
--with github.com/caddy-dns/duckdns 
--with github.com/caddy-dns/namecheap 
--with github.com/caddy-dns/dynv6 
--with github.com/caddy-dns/route53 
--with github.com/caddyserver/forwardproxy@caddy2=github.com/klzgrad/forwardproxy@naive

有其他需要加的插件可以提。
caddyfile配置文件:/data/caddyfile.txt,建议映射/data目录。
可用环境变量

1
2
3
4
# 设置时区
TZ=Asia/Shanghai
# 设置容器DNS(解析证书API接口)
DNS=223.5.5.5,8.8.8.8

示例caddy配置

  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
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
# 全局选项
{
    # 全局使用alidns
    acme_dns alidns {
                access_key_id 2znPBAveMAhVV5A75CTuaq
                access_key_secret 3Tf2oG2UonBCC4AQsfzytr3BxUMQ6La2D
        }
    # 使用dnspod token
    # acme_dns dnspod 37456,ejbe9tb5tiasjz2yu5u688vrwegpm
    # 使用cloudflare api token
    # acme_dns cloudflare v3ipam6idiwcmfub4iee4yjqyvykx
  
  # 储存目录默认映射
  storage file_system /data/cert
  # 注意storage目录文件默认权限不允许其他人访问
  # 如果需要被其他程序访问,可以自己手动chmod -R

  # 关闭http自动重定向,可避免出现80端口占用问题(可手动加重定向配置)
  auto_https disable_redirects
  
  # 尝试申请Google CA
  # 你需要到Google获取eab key来使用,详见:https://pki.goog/
  # eab key仅仅是使用这个服务的权限与域名无关,不管是哪个账号申请,都是通用的
  # 申请eab key不用会自动过期
  # 如果你有Google domains,可以一键申请https://domains.google.com
  # 注意:你需要自己解决https://dv.acme-v02.api.pki.goog/的科学访问
  # email exmaple@gmail.com
  # cert_issuer acme https://dv.acme-v02.api.pki.goog/directory  {
  #       eab <EAB_密钥_ID>  <EAB_HMAC_密钥>
  #   }
  #   失败回退常规acme
  #   cert_issuer acme
  
  # 屏幕打印日志,需要调试的时候可打开
  # log {
  #        output stdout
  #        format console
  #        level debug
  #    }
}

# 申请通配符证书,并反向代理到https://192.168.1.123,忽略https自签验证
*.example.com {
        reverse_proxy https://192.168.1.123 {
          transport http {
                  tls
                   tls_insecure_skip_verify
           }
        }
}

# 域名选项

# 单个域名反向代理,bind设置监听172.26.25.24地址,端口18888
admin.example.com:18888 {
bind 172.26.25.24
        reverse_proxy https://192.168.1.2:8888 {
           transport http {
                  tls
                  tls_insecure_skip_verify
           }
        }
}
# 把http请求重定向到https
http://admin.example.com:80 {
bind 172.26.25.24
redir * https://admin.example.com:18888 301
}

# 绑定多个域名
mail.example.com:1080 mail.example.lan:1080 {
        reverse_proxy http://192.168.1.201:18080 
}

# 静态文件服务/data/www,并且example.org/admin反向代理到http://127.0.0.1:8080
example.org {
        root * /data/www
        encode gzip
        file_server
        redir /admin  /admin/ 301
        reverse_proxy /admin/* http://127.0.0.1:8080 {
        header_up X-Real-IP {remote_host}
        }
}

# 静态文件服务/data/blog,自定义404页面
blog.example.org {
        root * /data/blog
        encode gzip
        file_server
        handle_errors {
                @404 {
                        expression {http.error.status_code} == 404
                }
                rewrite @404 404.html
                file_server
        }
}

# 首页反向代理127.0.0.1:8989,但重定向所有jpg后缀到另一个网站,其他请求回应404
www.example.org {
        reverse_proxy 127.0.0.1:8989
        redir /*.jpg https://img.example.org/post{uri} permanent
        respond  404
}

# 仅使用http
http://no.example.net {
    respond "Hello word !"
}

# 单独设置证书
ali.example.net {
    respond "Hello word !"
    tls {
         dns alidns {
           access_key_id 4cyPa9zBaCZAGS86qxTMz
           access_key_secret 4ypt8XM9cF3dGds5U7R7wQhWSJLoaMYCP
        }
    }
}
cf.example.net {
    respond "Hello word !"
    tls {
	    dns cloudflare kKMZgemtLrEpiG5r9igPPKRN6himKVau2iFbi
    }
}
dnspod.example.net {
    respond "Hello word !"
    tls {
     dns dnspod 45674,643mzcxv4k9c77rqqge4wocyydsn6
    }
}

# 手动指定外部证书,从/data/pems目录价值所有.pem文件
sign.cf.example.net {
    tls {
      load /data/pems
    }
}

# 添加header 例如HSTS
apple.exampe.com {
        header Strict-Transport-Security max-age=63072000
        respond "Hello HSTS !"
}

# 综合示例,复用URL
nas.example.com {

# 访问nas.example.com/blog,提供/data/blog目录的静态文件
        handle /blog/* {
                file_server {
                        root /data/
                }
        }
# 重定向不带/的路径到/
        redir /blog  /blog/ 301

# 访问nas.example.com/jsonrpc,代理aria2的jsonrpc
        handle /jsonrpc {
                reverse_proxy http://192.168.1.123:6800 
        }

# 访问nas.example.com/plex,代理plex服务
## 使用uri strip_prefix可以把请求中的/plex路径去掉
        handle /plex/* {
                uri strip_prefix /plex
                reverse_proxy  http://127.0.0.1:32400
        }
# 处理plex静态引用的web目录
        handle /web/* {
                reverse_proxy  http://127.0.0.1:32400
        }
# 重定向不带/的路径到/
          redir /plex  /plex/ 301

# 处理plex静态引用的media目录
        handle /media/* {
                reverse_proxy  http://127.0.0.1:32400
        }

# 代理nas的web管理服务 
        reverse_proxy * https://127.0.0.1:5001 {
                transport http {
                        tls
                        tls_insecure_skip_verify
                }
        }

 # 反向镜像代理,添加header_up       
        redir /trends  /trends/ 301
        handle /trends/* {
                uri strip_prefix /trends
                        reverse_proxy  https://trends.google.com {
                        header_up Host trends.google.com
                }
        }
  }

示例docker compose

注:先创建/share/Container/caddy/data/caddyfile.txt

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
version: '3'

services:
  caddy:
    pull_policy: always
    image: sliamb/caddy:latest
    container_name: caddy
    restart: unless-stopped
    environment:
      - TZ=Asia/Shanghai
      - DNS=223.5.5.5,8.8.8.8
    volumes:
      - /share/Container/caddy/data:/data
    network_mode: "host"

注:此处使用network_mode: "host"可直接访问宿主所有网络接口和端口,对于作为反向代理来说比较方便,编辑caddyfile.txt更直观,不需要额外映射地址端口。