内网环境或NAT环境下Caddy基于DNSPOD签发证书

纯个人喜好,Docker环境下比较喜欢Caddy,k8s环境下比较喜欢Traefik

前提条件

  • 域名托管在DNSPOD(腾讯云DNS)
  • 内网环境或者NAT环境(即没有办法使用HTTP-01方式签发证书)

通常来说(不负责任), 内网环境没必要使用证书。

本文演示环境为鸡仔云NAT,端口映射方式暴露Caddy HTTP(S)端口,使用非标准协议端口,故而只能使用DNS-01方式

简单科普

HTTP-01

适合简单、快速的验证,通常访问http://yourdomain.com/.well-known/.... 这个目录下的文件并验证其内容是否正确,然后签发证书,依赖80端口可被公网访问

DNS-01

添加TXT记录来验证域名

其他

如果域名托管在CF,还可以选择CF的15年证书

腾讯云DNS配置

创建普通用户

通常情况下,选择新建一个普通用户,只给编程访问权限, 其他默认即可

腾讯云访问管理

创建自定义策略

出于某些考虑,限制我这个API使用,只允许白名单IP(合法IP,示例可以理解为马赛克)可访问,不需要去掉即可

{
    "statement": [
        {
            "action": [
                "dnspod:DescribeDomainDigResult",
                "dnspod:DescribeDomainExistRecordList",
                "dnspod:DescribeRecord",
                "dnspod:DescribeRecordImpactInfo",
                "dnspod:CreateRecord",
                "dnspod:DeleteRecord"
            ],
            "condition": {
                "ip_equal": {
                    "qcs:ip": [
                        "2409:...",
                        "183..."
                    ]
                }
            },
            "effect": "allow",
            "resource": [
                "qcs::dnspod::uin/账号ID:domain/DomainID"
            ]
        }
    ],
    "version": "2.0"
}
  • 账号ID: 点击右上角主账号就可以看到了, 也可以通过账号中心/账号信息
  • DomainID: 云解析-域名设置中可看

关联策略

用户列表-关联策略,效果如下

完成之后,获取API密钥备用

构建Caddy镜像

目前情况下Caddy是不支持DNSPOD方式签发证书的。这里我提供一下我构建好的镜像

  • ccr.ccs.tencentyun.com/k7scn/caddy:2024

我还是推荐自行构建好,因为我会经常调整我的镜像,增删插件

构建Dockerfile如下

FROM ccr.ccs.tencentyun.com/k7scn/god AS builder

RUN go install github.com/caddyserver/xcaddy/cmd/xcaddy@latest

WORKDIR /go/src/

RUN xcaddy build \
            --with github.com/caddy-dns/cloudflare \
            --with github.com/caddy-dns/tencentcloud \
            --with github.com/caddy-dns/alidns \
            --with github.com/caddy-dns/dnspod

RUN /go/src/caddy list-modules

FROM ccr.ccs.tencentyun.com/k7scn/debian

COPY --from=builder /go/src/caddy /usr/bin/caddy

RUN chmod +x /usr/bin/caddy && \
  mkdir -p \
  /config/caddy \
  /etc/caddy \
  /data/caddy \
  /var/log/caddy

ENV XDG_CONFIG_HOME /config

ENV XDG_DATA_HOME /data

EXPOSE 80
EXPOSE 443
EXPOSE 443/udp

VOLUME /config

VOLUME /data

VOLUME /var/log/caddy

CMD caddy run --config /etc/caddy/Caddyfile --adapter caddyfile

结构还是比较清晰的

部署Caddy

使用compose方式部署镜像

services:

  caddy:
    image: ccr.ccs.tencentyun.com/k7scn/caddy:2024
    container_name: caddy
    volumes:
      - /etc/caddy:/etc/caddy
      - /var/log/caddy:/var/log/caddy
      - /data/caddy/data:/data
      - /data/caddy/config:/config
    ports:
      - "38080:38080"
      - "38443:38443"
    restart: always
    network_mode: "host"

给大家看下/etc/caddy目录结构

.
├── Caddyfile # 全局配置
├── site # 域名配置
│   ├── default.caddy
│   ├── tea.caddy
│   └── tts.caddy
└── ssl # CF15证书、自签证书或其他证书
    └── ysicing.eu.org
        ├── ysicing.key
        └── ysicing.pem

全局配置Caddyfile

主要定义了3个全局模块,方式域名里单独引用

(LOG) {
	log {
		output file "{args[0]}" {
			roll_size 50M
			roll_uncompressed
			roll_local_time
			roll_keep 3
			roll_keep_for 7d
		}
		format json
	}
}

(TLS) {
	tls {
		load /etc/caddy/ssl
	}
}

(CFIP) {
	@ip_whitelist {
		not remote_ip 2400:cb00::/32 2606:4700::/32 2803:f800::/32 2405:b500::/32 2405:8100::/32 2a06:98c0::/29 2c0f:f248::/32 fd7a:115c:a1e0::/96 173.245.48.0/20 103.21.244.0/22 103.22.200.0/22 103.31.4.0/22 141.101.64.0/18 108.162.192.0/18 190.93.240.0/20 188.114.96.0/20 197.234.240.0/22 198.41.128.0/17 162.158.0.0/15 104.16.0.0/13 104.24.0.0/14 172.64.0.0/13 131.0.72.0/22
	}
	route @ip_whitelist {
		respond 451
	}
}

{
	debug
	admin off
	http_port 38080
	https_port 38443
	email 邮箱(建议写上)
	acme_dns tencentcloud {
		secret_id "腾讯云AK"
		secret_key "腾讯云Key"
	}
}

import /etc/caddy/site/*.caddy

独立站点示例

这里以/etc/caddy/site/default.caddy简单说下,主要是对接CF的,设置了日志和IP访问策略

:38080 {
	import CFIP
	import LOG "/var/log/caddy/default-http.log"
	respond "http, cf: {remote_host}, ip: {http.request.header.CF-Connecting-IP}"
}

:38443 {
	import CFIP
	import LOG "/var/log/caddy/default-https.log"
	import TLS
	respond "tls, cf: {remote_host}, ip: {http.request.header.CF-Connecting-IP}"
}

验证我的想法可以访问ysicing.eu.org

其他站点按照Caddy的规则写就可以了,随便编个大概示例如下

nat.ysicing.net {
    import CFIP
    import LOG "/var/log/caddy/nat-ysicing-net.log"
    import TLS
    reverse_proxy http://127.0.0.1:3333
}

其他问题

由于使用非标准端口,默认配置是没办法实现http自动跳转https。

Sponsor

Like this article? $1 reward

Comments