
wemakeservices/caddy-gencaddy-gen是Caddy、docker-gen和forego的完美组合,灵感来源于nginx-proxy。它通过docker-gen监听容器生命周期事件,动态生成Caddy配置,解决了Caddy静态配置在应用扩展时的局限性,实现轻松扩展。
virtual.host指定主域名,支持空格分隔多个域名virtual.alias设置域名别名,自动重定向至主域名virtual.tls-email即可启用Let's Encrypt证书自动申请与续期caddy-gen通过Docker容器标签进行配置,核心思想是:每个带标签的服务通过virtual.host暴露域名,每个容器作为一个上游服务处理请求。
注意:v0.3.0版本引入Caddy2,带来不兼容变更。
| 标签 | 说明 |
|---|---|
virtual.host (必填) | 域名,无需包含http://或https://,多个域名用空格分隔 |
virtual.alias | 域名别名,如[***],会自动重定向至主域名 |
virtual.port | 容器暴露的端口,如React开发应用的3000 |
virtual.tls-email | ACME账户***,用于HTTPS证书管理(启用HTTPS必填) |
virtual.tls | virtual.tls-email的别名 |
virtual.host.directives | 自定义Caddyfile指令,内联到站点配置块 |
virtual.host.import | 从容器文件系统导入Caddyfile指令,需配合Caddy的import指令 |
同时配置以下标签启用HTTP基础认证:
virtual.auth.path:认证生效的路径virtual.auth.username:认证用户名virtual.auth.password:base64编码的bcrypt哈希密码(可通过bcrypt-generator.com生成哈希,再用base64encode.org编码)| 标签 | 说明 |
|---|---|
virtual.proxy.matcher | 仅匹配指定路径的请求进行反向代理 |
virtual.proxy.lb_policy | 负载均衡策略,默认round_robin |
virtual.proxy.directives | 反向代理相关的自定义指令 |
virtual.proxy.import | 从容器文件系统导入反向代理指令 |
通过环境变量支持自定义配置:
CADDY_TEMPLATE:挂载自定义模板文件路径,替换默认Caddy模板CADDY_SNIPPET:挂载自定义片段文件路径,内容会前置到模板中,用于设置全局选项、定义代码片段或添加自定义地址块支持通过构建参数自定义组件版本:
FOREGO_VERSION:指定forego版本DOCKER_GEN_VERSION:指定docker-gen版本以下示例通过docker-compose部署caddy-gen作为反向代理,代理whoami服务:
yamlversion: "3" services: caddy-gen: container_name: caddy-gen image: "wemakeservices/caddy-gen:latest" restart: always volumes: - /var/run/docker.sock:/tmp/docker.sock:ro # 需挂载Docker socket监听容器事件 - ./caddy-info:/data/caddy # 挂载卷备份证书 ports: - "80:80" - "443:443" depends_on: - whoami whoami: # 被代理的服务 image: "katacoda/docker-http-server:v2" labels: - "virtual.host=myapp.com" # 主域名(必填) - "virtual.alias=[***]" # 域名别名(可选) - "virtual.port=80" # 容器暴露端口 - "virtual.tls-email=***" # 启用HTTPS(必填***) - "virtual.auth.path=/secret/*" # 基础认证路径 - "virtual.auth.username=admin" # 基础认证用户名 - "virtual.auth.password=JDJ5JDEyJEJCdzJYM0pZaWtMUTR4UVBjTnRoUmVJeXQuOC84QTdMNi9ONnNlbDVRcHltbjV3ME1pd2pLCg==" # base64编码的bcrypt密码
为确保HTTPS证书持久化,需挂载/data/caddy目录:
yamlservices: caddy-gen: volumes: - ./caddy-info:/data/caddy # 证书将存储在本地./caddy-info目录
通过virtual.proxy.directives修改反向代理请求头,如下示例使上游服务获取自身地址:
yamlservices: whoami: labels: virtual.host: myapp.com virtual.port: 80 virtual.tls: *** virtual.proxy.directives: | header_up Host {http.reverse_proxy.upstream.hostport}
通过virtual.host.directives配置静态文件服务,如下示例使myapp.com提供www目录下的文件,并将/api/*请求代理到whoami服务:
yamlversion: "3" services: caddy-gen: image: "wemakeservices/caddy-gen:latest" restart: always volumes: - /var/run/docker.sock:/tmp/docker.sock:ro - ./caddy-info:/data/caddy - ./www:/srv/myapp/www # 挂载静态文件目录到容器 ports: - "80:80" - "443:443" depends_on: - whoami whoami: image: "katacoda/docker-http-server:v2" labels: virtual.host: myapp.com virtual.port: 80 virtual.tls: *** virtual.proxy.matcher: /api/* # 仅代理/api/*路径 virtual.host.directives: | root * /srv/myapp/www # 静态文件根目录 templates # 启用模板功能 file_server # 启用文件服务
以下示例自定义模板实现HTTPS重定向和按域名日志分割:
自定义模板文件(./caddy/template):
jinja(redirectHttps) { @http { protocol http } redir @http https://{host}{uri} } (logFile) { log { output file /var/caddy/{host}/logs { roll_keep_for 7 } } } {{ $hosts := groupByLabel $ "virtual.host" }} {{ range $h, $containers := $hosts }} {{ range $t, $host := split (trim (index $c.Labels "virtual.host")) " " }} {{ $tls = trim (index $c.Labels "virtual.tls") }} {{ $host }} { {{ if $tls }} tls {{ $tls }} import redirectHttps {{ end }} reverse_proxy { lb_policy round_robin {{ range $i, $container := $containers }} {{ range $j, $net := $container.Networks }} to {{ $net.IP}}:{{ or (trim (index $container.Labels "virtual.port")) "80" }} {{ end }} {{ end }} } encode zstd gzip import logFile }
docker-compose配置:
yamlservices: caddy-gen: volumes: - ./caddy/template:/tmp/caddy/template # 挂载模板文件 environment: CADDY_TEMPLATE: /tmp/caddy/template # 指定自定义模板路径
通过CADDY_SNIPPET设置全局选项,如下示例使用Let's Encrypt测试环境(避免证书申请频率限制):
全局选项片段文件(./caddy/global_options):
jinja{ acme_ca [***] }
docker-compose配置:
yamlservices: caddy-gen: volumes: - ./caddy/global_options:/tmp/caddy/global_options # 挂载片段文件 environment: CADDY_SNIPPET: /tmp/caddy/global_options # 指定片段路径



manifest unknown 错误
TLS 证书验证失败
DNS 解析超时
410 错误:版本过低
402 错误:流量耗尽
身份认证失败错误
429 限流错误
凭证保存错误
来自真实用户的反馈,见证轩辕镜像的优质服务