lego 集成 DirectAdmin DNS 提供商:配置详解与 TXT 挑战实现原理
2026/9/24 14:58:11 网站建设 项目流程
  • 网络安全
  • 密码学

【免费下载链接】lego

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

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

本文是一份面向开发者的 DirectAdmin DNS 提供商(Provider)使用指南。基于 lego(Let's Encrypt/ACME 客户端与库)官方文档 docs/content/dns/zz_gen_directadmin.md 及providers/dns/directadmin目录下的真实源码,说明如何通过环境变量配置 DirectAdmin 凭据、通过--dns directadmin完成 ACME DNS-01 挑战,以及该提供商在 lego 内部如何调用 DirectAdmin 的CMD_API_DNS_CONTROL接口增删 TXT 记录。读完本文,你将能够为运行在 DirectAdmin 控制面板上的域名签发单域名与通配符证书,并理解其底层工作原理。

DirectAdmin 提供商概述

DirectAdmin 是一款常见的服务器控制面板(官方站点为 https://www.directadmin.com),自带完整的 DNS 管理 API。lego 的 DirectAdmin 提供商(Provider Code:directadmin)从v4.18.0版本开始提供,用于通过 DNS-01 挑战方式验证域名所有权。

与 HTTP-01 挑战需要在 Web 服务器上放置验证文件不同,DNS-01 挑战要求在你的权威 DNS 区域中临时新增一条TXT记录。lego 会在挑战前调用 DirectAdmin API添加该 TXT 记录(Present),等待 DNS 传播完成后向 ACME 服务端验证,最后在挑战结束后删除该记录(CleanUp)。

该提供商的配置元数据定义在 providers/dns/directadmin/directadmin.toml 中,并已注册进 lego 的 DNS 提供商调度表(见 providers/dns/zz_gen_dns_providers.go,case "directadmin": return directadmin.NewDNSProvider())。

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

以 DirectAdmin 官方文档给出的示例命令为基准,使用环境变量传入 API 地址、用户名和密码,即可对*.example.comexample.com同时发起证书签发:

DIRECTADMIN_API_URL="http://example.com:2222" \ DIRECTADMIN_USERNAME=xxxx \ DIRECTADMIN_PASSWORD=yyy \ lego run --dns directadmin -d '*.example.com' -d example.com

说明:

  • lego run会完成注册、签发与自动续期的完整流程(如需查看所有可用参数,可运行lego run --help)。
  • 示例中同时传入'*.example.com'example.com,正是通配符证书的典型用法——ACME 要求通配符域名必须走 DNS-01 挑战。
  • DIRECTADMIN_API_URL:2222是 DirectAdmin 默认的控制面板端口;实际地址以你的服务器配置为准,务必确认该地址从 lego 运行所在主机可访问。

凭据配置(Credentials)

lego 的全部 DNS 提供商均通过环境变量注入凭据。DirectAdmin 提供商需要以下三个必填变量:

环境变量名说明
DIRECTADMIN_API_URLAPI 的 URL(如http://example.com:2222
DIRECTADMIN_USERNAMEAPI 用户名
DIRECTADMIN_PASSWORDAPI 密码

这些变量名在源码中以常量形式定义在 providers/dns/directadmin/directadmin.go(命名空间前缀DIRECTADMIN_),并由NewDNSProvider()通过env.Get(EnvAPIURL, EnvUsername, EnvPassword)一次性读取;缺少任何一个变量都会返回形如directadmin: some credentials information are missing: DIRECTADMIN_API_URL的错误(该行为由 directadmin_test.go 的用例逐项验证)。

使用_FILE后缀引用文件

所有环境变量(包括下文的附加配置项)都可以通过_FILE后缀改为从文件读取,从而避免在 shell 历史或进程列表中泄露密钥。例如:

DIRECTADMIN_API_URL_FILE=/path/to/api_url \ DIRECTADMIN_USERNAME_FILE=/path/to/username \ DIRECTADMIN_PASSWORD_FILE=/path/to/password \ lego run --dns directadmin -d '*.example.com'

其中每个文件内容仅允许包含该变量的值本身(不要包含换行或多余字符)。这一机制的通用说明见 docs/content/dns/_index.md(Configuration and Credentials一节),实现上由platform/envGetOrFile系列函数支撑,例如env.GetOrFile(EnvZoneName)(见 directadmin.go)。

使用 dotenv 文件

当使用配置文件或希望集中管理变量时,可以用--env-file指定 dotenv 文件:

lego run --dns directadmin --domains 'example.org' --domains '*.example.org' --env-file .env.directadmin

.env.directadmin内容示例:

DIRECTADMIN_API_URL=http://example.com:2222 DIRECTADMIN_USERNAME=xxxx DIRECTADMIN_PASSWORD=yyy

该方式同样适用于通过 lego 配置文件(.lego.yml)为 DNS 挑战块指定envFile的场景,具体约定参见 docs/content/dns/_index.md。

附加配置项(Additional Configuration)

除凭据外,DirectAdmin 提供商还支持以下可调参数,均通过环境变量注入:

环境变量名说明默认值
DIRECTADMIN_HTTP_TIMEOUTAPI 请求超时时间(秒)30
DIRECTADMIN_POLLING_INTERVALDNS 传播检查间隔(秒)5
DIRECTADMIN_PROPAGATION_TIMEOUTDNS 传播最大等待时间(秒)60
DIRECTADMIN_TTL挑战 TXT 记录的 TTL(秒)30
DIRECTADMIN_ZONE_NAME用于添加 TXT 记录的 Zone 名称自动探测

这些默认值与源码中NewDefaultConfig()的实现一一对应(directadmin.go):

func NewDefaultConfig() *Config { return &Config{ ZoneName: env.GetOrFile(EnvZoneName), TTL: env.GetOrDefaultInt(EnvTTL, 30), PropagationTimeout: env.GetOrDefaultSecond(EnvPropagationTimeout, 60*time.Second), PollingInterval: env.GetOrDefaultSecond(EnvPollingInterval, 5*time.Second), HTTPClient: &http.Client{ Timeout: env.GetOrDefaultSecond(EnvHTTPTimeout, 30*time.Second), }, } }

参数配置示例

DIRECTADMIN_API_URL="http://example.com:2222" \ DIRECTADMIN_USERNAME=xxxx \ DIRECTADMIN_PASSWORD=yyy \ DIRECTADMIN_TTL=60 \ DIRECTADMIN_POLLING_INTERVAL=10 \ DIRECTADMIN_PROPAGATION_TIMEOUT=120 \ DIRECTADMIN_HTTP_TIMEOUT=60 \ lego run --dns directadmin -d '*.example.com'

参数语义与调优建议

  • DIRECTADMIN_TTL:控制写入的 TXT 记录 TTL。该值通过internal.RecordTTL字段随 API 请求一起提交(见下文)。TTL 越大,解析缓存生效时间越长,可能拖慢挑战完成。
  • DIRECTADMIN_PROPAGATION_TIMEOUTDIRECTADMIN_POLLING_INTERVAL:lego 在写入记录后会轮询公共 DNS 直到记录可见。DNSProvider实现了challenge.ProviderTimeout接口,其Timeout()方法直接返回这两个配置(directadmin.go)。如果你的权威 NS 或公共解析器响应较慢,可适当调大超时。
  • DIRECTADMIN_ZONE_NAME:默认情况下 lego 通过dns01.DefaultClient().FindZoneByFqdn()根据待验证域名自动反查权威 Zone(见getZoneName实现,directadmin.go)。当自动探测失败,或你的 DirectAdmin 中所管理的 Zone 名称与公开 SOA 记录不一致时,可以显式指定,例如DIRECTADMIN_ZONE_NAME=example.com。注意代码中dns01.UnFqdn(authZone)会去掉域名末尾的点。

工作原理:从 Present 到 CMD_API_DNS_CONTROL

为了帮助你排查问题和评估安全性,这里结合源码梳理一次 DNS-01 挑战中该提供商的完整调用链。

1. Present:写入挑战 TXT 记录

Present()(directadmin.go)执行以下步骤:

  1. 通过dns01.GetChallengeInfo(ctx, domain, keyAuth)计算挑战记录:EffectiveFQDN_acme-challenge.<domain>)与ValuekeyAuth的摘要);
  2. 调用getZoneName确定权威 Zone(优先使用ZoneName配置,否则自动反查);
  3. dns01.ExtractSubDomain从完整 FQDN 中剥离出子域前缀(即_acme-challenge部分);
  4. 组装internal.Record{Name, Type: "TXT", Value, TTL}并调用client.SetRecord写入。

SetRecord(internal/client.go)将记录序列化为表单字段后追加action=add,然后发起请求。

2. 底层 HTTP 请求细节

所有写操作最终汇入Client.do()(internal/client.go),其请求特征:

  • 端点<BASE_URL>/CMD_API_DNS_CONTROL(DirectAdmin 标准 DNS 控制 API);
  • 方法POSTContent-Type: application/x-www-form-urlencoded
  • 认证:HTTP Basic Auth(req.SetBasicAuth(c.username, c.password));
  • 查询参数domain=<zone>&json=yes(请求 JSON 响应);
  • 表单字段nametypevaluettlaction
  • 错误处理:非 200 响应会被解析为 JSON 格式的APIErrorerror/result字段),返回如[status code 500] Cannot View Dns Record: OOPS的错误。

internal.Record的定义见 internal/types.go,字段与表单名一一对应。上述请求形态均由 internal/client_test.go 中的 mock 测试精确验证(包括domainjson=yesaction=addname/type/value/ttl等严格匹配)。

3. CleanUp:挑战完成后清理记录

CleanUp()(directadmin.go)与Present对称:重新计算EffectiveFQDN与子域,组装Record(注意此时不携带TTL),调用client.DeleteRecord(即action=delete)。即使挑战中途失败,lego 也会尽力调用CleanUp清理残留 TXT 记录。

以库的方式使用(Go 编程接口)

除了 CLI,你还可以把 DirectAdmin 提供商嵌入自己的 Go 程序。lego 通过lego.NewClient+client.Challenge.AddDNS01Provider组合使用,提供商侧提供两个构造入口:

import ( "github.com/go-acme/lego/v4/providers/dns/directadmin" "github.com/go-acme/lego/v4/lego" "github.com/go-acme/lego/v4/registration" ) // 方式一:从环境变量读取 DIRECTADMIN_API_URL / DIRECTADMIN_USERNAME / DIRECTADMIN_PASSWORD provider, err := directadmin.NewDNSProvider() if err != nil { // 缺少凭据时返回 directadmin: some credentials information are missing: ... } // 方式二:编程方式注入配置 config := directadmin.NewDefaultConfig() config.BaseURL = "http://example.com:2222" config.Username = "xxxx" config.Password = "yyy" config.TTL = 60 provider, err = directadmin.NewDNSProviderConfig(config) if err != nil { // 校验失败时返回 directadmin: missing API URL 等错误 }

注意NewDNSProviderConfig会进行必要的参数校验:BaseURL为空返回directadmin: missing API URL,用户名或密码缺失返回directadmin: some credentials information are missing(见 directadmin.go)。上述两种入口的成功与失败分支均有对应的单元测试覆盖(directadmin_test.go)。

常见问题排查要点

  • 提示some credentials information are missing:逐一确认DIRECTADMIN_API_URLDIRECTADMIN_USERNAMEDIRECTADMIN_PASSWORD三个变量都已正确导出(测试用例证明缺任意一个都会失败)。
  • 提示missing API URL:检查 URL 是否拼写完整(包含协议与端口),例如http://example.com:2222
  • API 返回 500 /Cannot View Dns Record:通常是 DirectAdmin 账号权限不足或登录信息有误,错误信息中会带上errorresult字段便于排查(参见 internal/types.go 与 client_test.go 的错误路径测试)。
  • Zone 自动探测失败:为待验证域名设置正确的 NS 记录并确保公网可解析;仍失败则显式设置DIRECTADMIN_ZONE_NAME
  • 超时类问题:DNS 传播较慢时增大DIRECTADMIN_PROPAGATION_TIMEOUT,同时可适当降低DIRECTADMIN_POLLING_INTERVAL提高轮询频率。

更多信息

  • DirectAdmin 官方 API 文档:https://www.directadmin.com/api.php(重点可关注CMD_API_DNS_CONTROLadd/delete动作)
  • 提供商配置元数据与示例:providers/dns/directadmin/directadmin.toml
  • 提供商主实现:providers/dns/directadmin/directadmin.go
  • API 客户端实现:providers/dns/directadmin/internal/client.go
  • 单元测试(含 mock 断言):providers/dns/directadmin/internal/client_test.go
  • 所有 DNS 提供商的通用配置(_FILE后缀、dotenv、配置文件约定):docs/content/dns/_index.md
  • 网络安全
  • 密码学

【免费下载链接】lego

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

项目地址:https://gitcode.com/gh_mirrors/le/lego
点击查看免费下载
上一篇:三步快速上手Windows微信群发工具:告别手动发送的终极解决方案
下一篇:猫抓(cat-catch)资源嗅探扩展:三步解决网页媒体下载难题

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

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

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

立即咨询