实战记录日期:2026 年 10 月 软件版本:acme2certifier 0.46.2(nginx-wsgi)/ Debian 13 / 1Panel + OpenResty / Windows AD CS。
本文目标:将现有 Windows AD CS 私有证书颁发机构转化为可供 1Panel 调用的 ACME 服务,实现内部 HTTPS 证书的自动申请、部署与续签。本文根据实际部署对话整理,区分“已实测通过”“示例配置”和“尚待验证”;账户密码、EAB HMAC 等敏感信息均不收录。
脱敏说明:本文涉及的 example.com、ad.example.net、192.168.50.0/24、ca01、Example Issuing CA、svc_certbot 和 example-1panel 均为演示值,不对应真实部署。不要将示例地址直接用于生产环境。
部署结果:已经通过 acme.sh 验证 AD CS 签发、通过 1Panel 自定义 ACME 账户完成 HTTP-01 证书申请并成功绑定站点,随后人工触发续签成功;ACME Directory 返回
externalAccountRequired: true。DNS-01 与泛域名证书方案最终决定暂缓。
一、整体架构与环境
1Panel / OpenResty (192.168.50.10)
├── HTTPS: https://acme.example.com/directory
│ ↓ 反向代理 HTTP
└────── acme2certifier (Debian 13, 192.168.50.20:8080)
↓ MS-ICPR / SMB 445, 使用 svc_certbot 认证
Windows AD CS
ca01.ad.example.net (192.168.50.30)
↓
Example Issuing CA
↓
Example Root CA(离线根 CA)
| 组件 | 本次部署使用的信息 |
|---|---|
| Active Directory 域 | ad.example.net |
| 网站/证书域名 | example.com;ACME 服务为 acme.example.com |
| Windows 证书服务器 | ca01.ad.example.net(192.168.50.30) |
| AD CS CA 名称 | Example Issuing CA(由离线 Root CA 签发) |
| ACME 虚拟机 | Debian 13,192.168.50.20 |
| 反向代理 | 1Panel/OpenResty,192.168.50.10 |
| 证书吊销/颁发者信息 | http://pki.example.com/pki/ |
| ACME 软件 | grindsa/acme2certifier:0.46.2-nginx-wsgi |
| 证书模板 | ExampleACMEWebServer,RSA 2048,90 天 |
本环境采用内部拆分 DNS:example.com 公网记录由腾讯云 DNS 管理,内部同名区域由 AD DNS 管理;ad.example.net 仅使用 AD DNS。HTTP-01 测试时,ACME 服务器必须能正确解析目标域名并访问目标 Web 服务的 80 端口。
二、Windows AD CS:准备证书模板和签发账户
1. 确认 CA 服务
在 Windows CA 服务器上确认 CA 名称是 ca01.ad.example.net\Example Issuing CA;确认根证书与 Issuing CA 证书链有效,CRL/AIA 发布正常。
certutil -getconfig
certutil -CATemplates
2. 创建并发布专用证书模板
- 从 Web Server 模板复制出
ExampleACMEWebServer。 - 用途保持 Server Authentication;申请者使用 RSA 2048 私钥。
- 主题名称采用 Supply in the request,让 ACME CSR 提供 CN/SAN。
- 模板有效期设置为 90 天;不要求人工批准。
- 在模板安全页,为专用域账户
svc_certbot@ad.example.net授予 Read 与 Enroll,不要为了签发证书而赋予域管理员权限。 - 在 CA 控制台的 Certificate Templates 节点发布该模板,并使用
certutil -CATemplates检查已发布。
如出现模板“拒绝访问”,重点检查模板 ACL、CA 是否发布模板、申请账号是否具有 Enroll。模板自动注册(Autoenroll)与本次通过 MS-ICPR 申请证书不是一回事,不应把自动注册失败直接当成 ACME 签发失败。
3. CA 服务器和网络前提
acme2certifier 必须能解析 ca01.ad.example.net 并使用 MS-ICPR 连接 CA,部署中采用 NTLM 认证(use_kerberos = False);长期使用建议评估 Kerberos。检查 Debian 到 CA 的 TCP 445 连接,并确保服务账号及密码正确。
getent ahostsv4 ca01.ad.example.net
nc -zvw3 192.168.50.30 445
三、Debian 13:部署 acme2certifier
1. 安装 Docker 并准备目录
本次部署使用 Docker/Compose,相关工作目录为 /opt/acme2certifier。以下命令用于检查运行环境;Docker 的具体安装可按照当前 Debian 官方/Docker 官方步骤完成。
docker --version
docker compose version
mkdir -p /opt/acme2certifier/data
cd /opt/acme2certifier
2. Compose 参考文件
下面是与本次部署架构一致的示例;以实际运行的 compose.yaml 为准,尤其是数据卷和环境变量挂载。部署日志曾显示容器端口为 0.0.0.0:8080->80/tcp;在完全内网条件下可以使用,但不宜将该端口直接开放到公网。
services:
acme-srv:
image: grindsa/acme2certifier:0.46.2-nginx-wsgi
container_name: acme2certifier
restart: unless-stopped
ports:
- "8080:80"
env_file:
- ./adcs.env
volumes:
- ./data:/var/www/acme2certifier/volume
在 /opt/acme2certifier/adcs.env 中保存 AD CS 服务账号口令,真实口令不要写到博客、Git 仓库、Compose 文件正文或故障排查截图中。
A2C_ADCS_PASSWORD=<请填写服务账号真实口令>
chmod 600 /opt/acme2certifier/adcs.env
docker compose up -d
docker compose ps
docker compose logs --tail=80
3. 配置 CA Handler
本次运行中确认使用了 MS-ICPR CA Handler,示例中的关键参数如下。注意:请将下面的内容与现有配置合并,而不是覆盖完整的 acme_srv.cfg;原文件中还可能有数据库、目录、验证及 EAB 相关设置。
[DEFAULT]
server_name = acme.example.com
[CAhandler]
handler_module = acme2certifier.cahandlers.msicpr_ca_handler
host = ca01.ad.example.net
target_domain = ad.example.net
ca_name = Example Issuing CA
user = svc_certbot
password_variable = A2C_ADCS_PASSWORD
use_kerberos = False
template = ExampleACMEWebServer
allowed_domainlist = ["acme-test.example.com", "acme.example.com"]
[Challenge]
challenge_validation_disable = False
http01_block_private_ips = False
http01_block_private_ips = False 是为了允许本次 ACME 服务验证内网目标 IP;只适用于可信任的内部部署场景。务必保留真实的挑战验证,不要以 challenge_validation_disable = True 来绕过验证。配置修改后重启容器。
cd /opt/acme2certifier
docker compose restart
curl -fsS http://192.168.50.20:8080/directory | python3 -m json.tool
四、使用 acme.sh 验证 AD CS 真实签发
正式接入 1Panel 之前,曾先通过 acme.sh 使用 HTTP-01 standalone 模式申请测试证书。测试域名 acme-test.example.com 指向 ACME 测试服务器 192.168.50.20;客户端在验证期间需能监听 TCP 80,且 ACME 服务端能够访问它。
cd /opt/acme-sh
./acme.sh --issue --standalone \
--server http://192.168.50.20:8080/directory \
-d acme-test.example.com \
--keylength 2048
这一步实际成功拿到了由 Example Issuing CA 签发的 RSA 2048、90 天证书,AD CS 曾记录到对应签发请求(可在 Windows AD CS 中查看对应签发请求)。随后对 acme.example.com 也完成过签发;最初因为内部 DNS 返回 NXDOMAIN 失败,添加正确记录后成功。
注意:上述命令对应早期的基础联通性测试。后续开启 EAB 严格模式后,新 ACME 账户注册需要有效的 KID/HMAC,不能直接假设未经 EAB 注册的 acme.sh 客户端还能正常使用。
五、1Panel/OpenResty:配置正式 HTTPS ACME 入口
1. 配置 DNS 与反向代理
- 内部 DNS 将
acme.example.com解析到 1Panel/OpenResty 的192.168.50.10,而不是直接指向后台192.168.50.20。 - 在 1Panel 建立
acme.example.comHTTPS 网站,反向代理到http://192.168.50.20:8080。 - 保留 Host 及客户端信息,确保
X-Forwarded-Proto为https,并检查 ACME Directory 输出的 URL 均为https://acme.example.com/...。 - HTTP-01 使用的
http://<目标域名>/.well-known/acme-challenge/...必须由受验证网站正确响应;不能把所有目标域名的挑战路径误转发到 ACME API。
正式的 ACME Directory 地址:https://acme.example.com/directory。在证书受信任的终端运行:
curl -fsS https://acme.example.com/directory | python3 -m json.tool
2. 处理自签私有根 CA 信任问题
最初在 1Panel 创建自定义 ACME 账户时出现 x509: certificate signed by unknown authority。原因是请求 ACME Directory 的 1Panel 宿主环境尚未信任 Example 根 CA 链。解决方式是将正确的私有 Root CA 导入发起请求的 1Panel 后端运行环境的受信任根证书存储,并检查证书链;不是简单关闭 TLS 校验。修复后用户已确认自定义 ACME 账户创建成功。
六、EAB:保护 ACME 账户注册
本次为 ACME 服务启用了 External Account Binding (EAB)。早期测试 KID 为 acme-lab-test,后续计划规范化为 example-1panel。不要直接将已注册并被 1Panel 续签使用的 KID 改名或删除,应新建 KID、在 1Panel 注册新账户、签发并绑定新证书,验证完成后再退出旧账户。
EAB Handler 的实际路径、JSON Profile 权限格式应以运行实例与对应版本文档核对。此次对话已确认开启严格模式后的 Directory 响应如下:
{
"meta": {
"name": "acme2certifier",
"version": "0.46.2",
"externalAccountRequired": true
}
}
这里的 externalAccountRequired: true 说明服务要求新 ACME 账户进行外部账户绑定,但不能单凭这项信息证明每个 KID 的 CA 模板、域名白名单已按预期生效。关于 kid_profile_handler 的细粒度权限,本次曾给出 example-1panel 覆盖 example.com 与 ad.example.net 的配置方案,尚没有贴出完整的正向与越权拒绝实测结果,因此本稿标记为“待补验证”。
七、1Panel 自定义 ACME 账户、申请与续签
1. 创建自定义账户
1Panel → 网站 → 证书 → ACME 账户 → 创建,类型选择“自定义 ACME 服务”,URL 使用 https://acme.example.com/directory;密钥算法选 RSA 2048,按 EAB 策略填写 KID 与 HMAC。已确认账户创建成功。EAB HMAC 不应进入 WordPress 正文或截图。
2. 申请证书
1Panel → 网站 → 证书 → 申请证书,选择新建的自定义 ACME 账户,目标域名 acme.example.com,验证方式 HTTP,勾选自动续签。实际申请日志关键部分如下:
YYYY/MM/DD 16:26:44 开始申请证书,域名 [acme.example.com],方式 [HTTP]
YYYY/MM/DD 16:26:44 [INFO] acme: Obtaining bundled SAN certificate
YYYY/MM/DD 16:26:44 [INFO] acme: use http-01 solver
YYYY/MM/DD 16:26:45 [INFO] The server validated our request
YYYY/MM/DD 16:26:45 [INFO] acme: Validations succeeded; requesting certificates
YYYY/MM/DD 16:26:46 [INFO] Server responded with a certificate.
YYYY/MM/DD 16:26:46 申请 [acme.example.com] 证书成功
随后在 1Panel 的 网站 → HTTPS 将新申请的证书绑定到 acme.example.com,验证服务仍正常访问。后来又由用户手动触发 1Panel 续签并确认成功,因此“签发、部署、手动续签”三项均已实测。自动续期调度本身需继续随到期时间观察,不应将单次手动续签视为未来定时任务的永久保证。
3. 在服务器上核实正在使用的证书
echo | openssl s_client \
-connect 192.168.50.10:443 \
-servername acme.example.com \
2>/dev/null | openssl x509 \
-noout -subject -issuer -serial -dates
预期签发者 CN 为 Example Issuing CA。需要注意:系统能读取证书不等于信任链自动可信;使用方仍需要信任 Example Root CA,并能按需访问 CRL/AIA。
八、常见问题与排查记录
| 现象 | 原因/处理 |
|---|---|
1Panel 创建 ACME 账户报 x509: certificate signed by unknown authority |
导入 Example 私有根 CA 至发起 ACME 请求的 1Panel 运行环境,检查签发链和服务端证书。 |
首次为 acme.example.com 申请时报 NXDOMAIN |
检查内部 AD DNS 正向区域与实际 A 记录;ACME 服务必须能正确解析验证目标。 |
| HTTP-01 验证失败 | 检查目标主机的 80 端口、DNS 解析、/.well-known/acme-challenge/ 响应是否由 1Panel 正确提供。 |
| EAB 严格模式生效但 Profile 权限不确定 | 先检查加载的 Handler 和非敏感策略,再分别测试授权域名签发成功与未授权域名被拒绝。 |
| 1Panel 证书列表“颁发组织”为空 | 本次签发 CA 只有 CN=Example Issuing CA,没有组织 O 字段;证书本身与续签均正常,属界面元数据呈现问题,不需要重新签发 CA。 |
| 修改配置后 Directory 正常,但不清楚后端是否真正生效 | /directory 只验证入口可用;结合容器日志、CA 请求记录及真实签发/拒绝测试判断。 |
九、运维与安全注意事项
- 备份
/opt/acme2certifier/中的 Compose 文件、配置、持久化数据库和 EAB Profile,并限制备份访问权限;本环境可使用 PVE/PBS 做虚拟机级定期备份。 - 严禁在 WordPress、公开仓库或日志分享中公开
adcs.env、服务账号密码、EAB HMAC、账户私钥等秘密。 - 服务当前以内网使用为主,Docker
8080端口曾监听所有接口;如果未来增加公网路由、端口映射或不可信客户端,应再收紧访问范围。 - 不要取消 HTTP-01 验证,也不要向 ACME 服务授予不必要的 AD 管理权限。
- 现有
example.com使用腾讯云公网 DNS + AD 内网 DNS,ad.example.net仅使用 AD DNS。DNS-01、通配符证书和 AD DNS 动态 TXT 自动化均已决定暂缓;当前以 HTTP-01 申请普通主机证书为主。 - 关于
example-1panel允许两个域名及子域名的独立授权,需补做边界测试后再标记为完成。
十、验收清单与最终状态
| 项目 | 本次对话状态 |
|---|---|
| AD CS 专用模板与服务账户 | 已配置并完成真实签发测试 |
| acme2certifier 0.46.2 容器 | 已运行并返回正常 ACME Directory |
| 1Panel HTTPS 反向代理 | 已验证 |
| 私有根 CA 信任及 1Panel 自定义 ACME 账户 | 已解决并成功创建 |
HTTP-01 申请 acme.example.com |
成功 |
| 1Panel 网站绑定新证书 | 成功 |
| 1Panel 手动续签 | 成功 |
| EAB 严格模式 | Directory 显示 externalAccountRequired: true |
按 KID 隔离 example.com / ad.example.net 权限 |
尚待完整正反例测试 |
| DNS-01 / 泛域名证书 | 暂缓 |
| 长期定时自动续签可靠性 | 已开启自动续签设置;持续观察 |
参考资料
本篇已对真实域名、AD 域、服务器名称、内网 IP、CA 名称、证书模板、服务账号及 EAB KID 进行示例化处理。示例域名 example.com 与 ad.example.net、示例 IP 192.168.50.0/24 不代表实际环境;实际操作须替换为自己的有效配置,并重新核对当前版本文档。

Comments NOTHING