使用 lego 的 Hetzner DNS Provider 签发 ACME 证书:配置、凭据与源码实现解析
2026/9/24 13:50:52 网站建设 项目流程
  • 网络安全
  • 密码学

【免费下载链接】lego

Let's Encrypt/ACME client and library written in Go

项目地址:https://gitcode.com/gh_mirrors/le/lego
点击查看免费下载

本指南完整讲解 Go 编写的 Let's Encrypt/ACME 客户端 lego 中 Hetzner DNS 提供商(provider code:hetzner)的配置与使用:包括获取 API Token、通过 DNS-01 挑战为域名(含通配符域名)签发证书的命令行示例、全部可调环境变量及其默认值、_FILE后缀与 dotenv 等凭据加载方式,并结合仓库源码剖析其底层调用链(Hetzner Cloud API 的 RRSet 操作与 action 轮询机制),帮助你快速落地并在遇到问题时能定位到具体实现。

Hetzner Provider 概览

Hetzner 是 lego 官方内置的 DNS-01 挑战提供商之一,自v3.7.0起可用(见 hetzner.toml)。它的作用是在 Hetzner DNS 中自动创建/删除 ACME 挑战所需的TXT记录,从而让 lego 无需人工干预即可完成 DNS-01 验证并签发证书。

在 lego 的 DNS 提供商目录(docs/content/dns/_index.md)中,Hetzner 被登记为:

属性
Code(命令行中使用名)hetzner
引入版本v3.7.0
官方站点hetzner.com

从源码结构看(providers/dns/hetzner/),该 provider 由统一入口hetzner.go对接到两套内部实现:

  • internal/hetznerv1/:基于Hetzner Cloud APIhttps://api.hetzner.cloud/v1),使用HETZNER_API_TOKEN,是当前推荐路径;
  • internal/legacy/:基于旧的Hetzner DNS APIhttps://dns.hetzner.com),使用HETZNER_API_KEY,已被标记为废弃(deprecated)。

两套实现都实现了 lego 的challenge.ProviderTimeout接口(Present/CleanUp/Timeout),对外行为一致,下文会分别说明其内部差异。

快速开始:签发通配符证书

在 Hetzner Cloud 控制台创建 API Token 后,使用官方文档给出的命令即可发起证书签发:

HETZNER_API_TOKEN="xxxxxxxxxxxxxxxxxxxxx" \ lego run --dns hetzner -d '*.example.com' -d example.com

要点说明:

  • --dns hetzner指定使用本 provider,-d(等价于--domains)声明要签发证书的域名;同时给出*.example.comexample.com可签发覆盖根域与所有子域的通配符证书,这正是 DNS-01 挑战相对 HTTP-01 的核心优势——无需对外暴露 80/443 端口。
  • lego 会自动完成:在 Hetzner 中添加挑战TXT记录 → 等待 DNS 传播 → 向 ACME 服务器发起验证 → 验证通过后清理TXT记录。
  • 若想先了解该 provider 支持的全部 CLI 选项,可运行lego run --help查看--dns相关参数,详见参考文档 ref-flags。

凭据配置:HETZNER_API_TOKEN

Hetzner provider 唯一必需的凭据环境变量是HETZNER_API_TOKEN(API token),可在 Hetzner Cloud 项目中创建并授予 DNS 读写权限。

基础用法与_FILE后缀

所有凭据类环境变量都支持两种取值方式:

  • 直接给值:

    HETZNER_API_TOKEN="xxxxxxxxxxxxxxxxxxxxx" lego run --dns hetzner -d example.com
  • 引用文件(变量名追加_FILE后缀,文件内容即凭据值,文件内只能包含该值本身):

    HETZNER_API_TOKEN_FILE=/etc/lego/hetzner_token \ lego run --dns hetzner -d example.com

    该机制对后文所有HETZNER_*变量均适用,相关约定详见 DNS Providers 文档 的 "Configuration and Credentials" 一节。

使用 dotenv 文件

当凭据较多或希望与命令解耦时,可用--env-file加载 dotenv 文件(格式为KEY=value,每行一个):

lego run --dns hetzner -d example.com --env-file .env.hetzner

.env.hetzner内容示例:

HETZNER_API_TOKEN=xxxxxxxxxxxxxxxxxxxxx HETZNER_TTL=120

使用配置文件(.lego.yml)

如果使用 lego 的 YAML 配置文件(见 file-configuration),可在 DNS 挑战段声明 provider,并通过envFile指定 dotenv 路径:

challenges: hetzner-challenge: dns: provider: hetzner envFile: .env.hetzner certificates: example: domains: - example.com - '*.example.com'

之后直接运行lego即可。

凭据缺失时的行为

从测试用例(hetzner_test.go)可以看到,若HETZNER_API_TOKENHETZNER_API_KEY均为空,NewDNSProvider()会返回错误hetzner: some credentials information are missing: HETZNER_API_TOKEN;而在NewDNSProviderConfig路径下则返回hetzner: credentials missing(见 hetzner.go)。因此排错时应优先检查 Token 是否已正确注入环境。

附加配置参数

除凭据外,Hetzner provider 还支持以下可调参数(均通过环境变量设置,同样支持_FILE后缀):

环境变量说明默认值
HETZNER_HTTP_TIMEOUTAPI 请求超时(秒)30
HETZNER_POLLING_INTERVALDNS 传播检查间隔(秒)2
HETZNER_PROPAGATION_TIMEOUT等待 DNS 传播的最大时长(秒)60
HETZNER_TTLDNS 挑战 TXT 记录的 TTL(秒)120

这些默认值在源码中有明确落点:

  • HETZNER_HTTP_TIMEOUT(30s):见 hetzner.go,构造http.Client时读取。
  • HETZNER_POLLING_INTERVAL(2s)与HETZNER_PROPAGATION_TIMEOUT(60s):直接对应 lego 全局常量dns01.DefaultPollingIntervaldns01.DefaultPropagationTimeout(见 dns_challenge.go)。
  • HETZNER_TTL(120s):对应dns01.DefaultTTL(见 dns_challenge.go)。

配置示例:

HETZNER_API_TOKEN="xxxxxxxxxxxxxxxxxxxxx" \ HETZNER_TTL=60 \ HETZNER_PROPAGATION_TIMEOUT=120 \ HETZNER_POLLING_INTERVAL=2 \ HETZNER_HTTP_TIMEOUT=30 \ lego run --dns hetzner -d example.com

注意 TTL 的下限约束:在 legacy(HETZNER_API_KEY)实现中,TTL 被硬性要求不小于 60 秒,否则NewDNSProviderConfig直接返回错误invalid TTL, TTL (N) must be greater than 60(见 internal/legacy/hetzner.go)。因此当你想调低 TTL 加速传播时,需留意 legacy 路径会拒绝小于 60 的值。

源码级实现解析

双 API 的自动选择逻辑

统一入口NewDNSProvider()根据环境变量决定走哪套实现(hetzner.go):

  1. 检测到HETZNER_API_TOKEN→ 使用hetznerv1(Hetzner Cloud API);
  2. 否则检测到HETZNER_API_KEY→ 使用legacy(旧 Hetzner DNS API),并打印警告APIKey (legacy Hetzner DNS API) is deprecated, please use APIToken (Hetzner Cloud API) instead.
  3. 两者都未设置 → 尝试创建hetznerv1provider,最终因缺少凭据而失败。

如果同时设置了 Token 与 Key,Token 优先(见测试用例 "success (both)",hetzner_test.go)。因此新用户应统一使用HETZNER_API_TOKENHETZNER_API_KEY仅用于兼容旧脚本。

v1:基于 Cloud API 的 RRSet 操作

hetznerv1实现(hetznerv1.go)的挑战流程如下:

  1. 定位授权区dns01.DefaultClient().FindZoneByFqdn()找到域名所属 zone;随后用dns01.ExtractSubDomain()拆出子域,并用idna.ToASCII处理国际化域名(IDN)。
  2. 添加记录:调用AddRRSetRecords,通过POST /zones/{zone}/rrsets/{name}/TXT/actions/add_records在现有 RRSet 上追加挑战记录(internal/client.go)。TXT 记录值会先经strconv.Quote包装,符合 TXT 记录的引号规范。
  3. 等待 action 完成:Hetzner Cloud API 的 RRSet 修改是异步的,返回一个ActionwaitActionHETZNER_POLLING_INTERVAL为周期轮询GET /actions/{id},直到状态变为success;若为errorrunning持续超过HETZNER_PROPAGATION_TIMEOUT则返回错误(hetznerv1.go)。轮询采用指数退避(backoff)库实现。
  4. 验证后清理CleanUp调用RemoveRRSetRecordsPOST .../actions/remove_records)删除相同记录,同样等待 action 完成。

请求鉴权通过 OAuth2 静态 Token(Bearer)注入(internal/client.go),请求/响应的 JSON 编解码与错误解析都在该 client 中完成,错误信息会带上 Hetzner API 返回的codemessage与字段级详情。

legacy:基于旧 DNS API 的记录操作

legacy实现(internal/legacy/hetzner.go)的流程更直接:

  1. 通过GetZoneIDGET /api/v1/zones?name=...中按域名找到 zone ID;
  2. CreateRecord直接POST /api/v1/records创建 TXT 记录;
  3. CleanUpGetTxtRecord按名称与值匹配记录,再DeleteRecord删除(DELETE /api/v1/records/{id})。

鉴权方式是把 API Key 放在自定义请求头Auth-API-Token中(internal/client.go)。由于该 API 已废弃,建议尽快迁移到HETZNER_API_TOKEN

排错与提示

  • DNS 传播检查:lego 在添加记录后等待HETZNER_PROPAGATION_TIMEOUT(默认 60s),若你的 DNS 服务器刷新较慢可适当调大该值与HETZNER_POLLING_INTERVAL的比值。
  • zone 定位失败:报错could not find zone for domain时,先确认该域名确实托管在 Hetzner DNS 且 Token 有对应 zone 的权限(见 hetznerv1.go)。
  • 多 SOA 环境:当 zone 同时存在内网与公网解析(多个权威服务器)时,可用--dns.resolvers指定外部权威解析器,例如lego run --dns hetzner --dns.resolvers 9.9.9.9:53 -d example.com,避免传播检测命中内网记录,详见 DNS-01 挑战指南 与 tips。
  • 请求超时HETZNER_HTTP_TIMEOUT只控制单次 HTTP 请求超时;传播等待总时长由HETZNER_PROPAGATION_TIMEOUT控制,两者职责不同。
  • 调试:lego 默认会在出错时打印 HTTP 请求/响应摘要(client 层通过clientdebug.Wrap包装),可结合 log 的调试级别观察实际 API 交互。

参考文档

  • Hetzner provider 自动生成文档(本文依据)
  • DNS Providers 总览与环境变量约定
  • DNS-01 挑战使用指南
  • Provider 入口实现
  • v1 实现与 RRSet 操作
  • legacy 实现
  • Provider 选择逻辑测试
  • 配置模板 hetzner.toml
  • 网络安全
  • 密码学

【免费下载链接】lego

Let's Encrypt/ACME client and library written in Go

项目地址:https://gitcode.com/gh_mirrors/le/lego
点击查看免费下载
上一篇:如何把魔百盒电视盒改成 Linux 服务器
下一篇:vinext是什么?用Vite插件运行Next.js应用的终极入门指南

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询