news 2026/9/10 1:35:35

Nginx Proxy Manager 证书全指南:HTTP / DNS 验证与自定义证书实战解析

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
Nginx Proxy Manager 证书全指南:HTTP / DNS 验证与自定义证书实战解析

Nginx Proxy Manager 证书全指南:HTTP / DNS 验证与自定义证书实战解析

【免费下载链接】nginx-proxy-managerDocker container for managing Nginx proxy hosts with a simple, powerful interface项目地址: https://gitcode.com/GitHub_Trending/ng/nginx-proxy-manager

本篇技术指南以 Nginx Proxy Manager 的官方帮助文档(前端帮助文档)为主线,系统讲解证书管理模块的三大核心方案:Let's Encrypt HTTP 验证证书、Let's Encrypt DNS 验证证书(含 Wildcard 通配符支持)以及自定义证书上传。文章不仅覆盖每一步操作流程,还将结合仓库中 证书后端实现、API 路由、DNS 插件清单 与前端表单组件,深入剖析每种方案背后的底层工作原理,帮助你理解"证书为什么这样申请、何时该选哪种方式、失败时如何排查",从而在真实生产环境中做出正确选择。

三种证书方案一览

Nginx Proxy Manager(NPM)的"证书(Certificates)"页面提供了三种创建证书的方式,它们分别对应不同的验证链路与适用场景:

方案验证方式是否支持通配符是否需要先建 Proxy Host代表场景
HTTP 证书(Let's Encrypt via HTTP)HTTP 文件验证已有公网可达的反向代理域名
DNS 证书(Let's Encrypt via DNS)DNS TXT 记录验证通配符证书、内网/未开放 80 端口、CDN 后置站点
自定义证书(Custom)由你的 CA 签发由证书本身决定企业级证书、付费证书、内部 PKI

三者最终都以provider字段区分:letsencryptother。在 证书数据模型 中,证书记录包含providernice_namedomain_namesexpires_onmeta等核心字段,其中meta用于保存 DNS 挑战信息、私钥内容、密钥类型等扩展属性,其完整结构定义在 certificate-object.json。

HTTP 验证证书(HTTP Certificate)

工作原理:Let's Encrypt 如何验证域名归属

HTTP 验证(HTTP-01 Challenge)的流程是:Let's Encrypt 的服务器会**通过 HTTP(而非 HTTPS)**访问你的域名,若访问成功并取到预期的令牌内容,即认定你拥有该域名,随后签发证书。

在 Nginx Proxy Manager 中,这一过程由 requestLetsEncryptSsl 方法驱动,其核心是通过certbot certonly命令,配合--authenticator webroot--preferred-challenges http参数完成验证。整个申请过程还会经历以下 6 个步骤(见 create 方法 中的注释):

  1. 找出所有使用了本证书域名的 Host(getHostsWithDomains);
  2. 将这些 Host 在 Nginx 中临时禁用disableInUseHosts);
  3. 生成临时的 Let's Encrypt 请求配置(generateLetsEncryptRequestConfig);
  4. 调用 certbot 申请证书;
  5. 删除临时的 LE 配置(deleteLetsEncryptRequestConfig);
  6. 重新启用之前禁用的 Host(enableInUseHosts)。

这一"临时禁用"策略是有意为之:证书申请期间,Nginx 必须只响应 ACME 挑战请求,因此需要临时生成一个仅监听 80 端口的虚拟主机。该配置由 letsencrypt-request.conf 模板生成,其中server_name直接绑定本次申请的全部域名,并通过include conf.d/include/letsencrypt-acme-challenge.conf暴露 ACME 挑战目录;其余所有请求统一return 404,避免影响挑战验证结果。

前置条件:必须先创建指向本机的 Proxy Host

这是 HTTP 验证方式最容易踩坑的地方。由于 Let's Encrypt 是从公网发起 HTTP 访问,因此你必须为待签发证书的域名先创建一个 Proxy Host,且满足:

  • 该 Host 必须能通过 HTTP(80 端口)访问;
  • 该 Host 必须指向当前这台 Nginx Proxy Manager 实例。

证书签发成功后,你可以修改该 Proxy Host,让它同时使用此证书提供 HTTPS 服务。但请务必记住:该 Proxy Host 必须始终保留 HTTP 访问配置,否则后续证书续期(Renew)时 ACME 挑战将无路可走,导致续期失败。

操作步骤

  1. 进入Certificates页面,点击Add SSL Certificate,选择Let's Encrypt Certificate
  2. 在弹出的 HTTPCertificateModal 表单中填写域名列表(Domain Names)
  3. 选择密钥类型(Key Type)rsaecdsa(默认ecdsa,详见下文说明);
  4. 可选:点击Test按钮,对域名做 HTTP 可达性预检;
  5. 点击Save保存并触发签发请求。

值得注意的是,NPM 在保存前内置了一个 HTTP 挑战预检功能:testHttpsChallenge(backend/internal/certificate.js)会在.well-known/acme-challenge目录写入测试文件,再通过外部服务发起 HTTP 探测。前端会根据返回结果展示五类诊断信息(见 HTTPCertificateModal.tsx):

探测结果含义
ok可达且返回内容正确,可以申请
no-host域名解析不到主机,检查 DNS
404主机可达但返回 404,检查站点配置
wrong-data返回内容不是预期令牌
failed/other:*探测本身失败或返回未知状态码

重要限制:不支持通配符

HTTP 验证过程不支持 Wildcard(通配符)域名。原因很直接:HTTP-01 挑战需要精确匹配具体主机名,*.example.com无法通过 HTTP 方式完成验证。如果需要*.example.com这类通配符证书,必须改用下面的 DNS 验证方式。

DNS 验证证书(DNS Certificate)

工作原理:通过 DNS 插件自动添加 TXT 记录

DNS 验证(DNS-01 Challenge)的核心思路是:你使用某个DNS Provider 插件,插件会在你的域名解析服务商处自动创建一条临时的 TXT 记录;Let's Encrypt 随后查询该记录,确认你对该域名具备控制权后签发证书。验证完成后,NPM 会清理掉这条临时记录。

整个流程由 requestLetsEncryptSslWithDnsChallenge 驱动。它的特别之处在于:

  • 会先调用installPlugin安装对应的 certbot DNS 插件(插件清单见 dns-plugins.json);
  • 将你填写的dns_provider_credentials0600权限写入/etc/letsencrypt/credentials/credentials-<certificate_id>,避免凭证泄露(0600仅允许属主读写);
  • 调用certbot certonly并指定--preferred-challenges dns与对应插件的--authenticator
  • 支持通过meta.propagation_seconds自定义 DNS 传播等待时间(默认值视插件而定),等待时间不足时验证可能失败;
  • Route 53 插件比较特殊:它不通过--credentials参数,而是通过环境变量AWS_CONFIG_FILE注入凭证(见 getAdditionalCertbotArgs)。

由于验证完全发生在 DNS 层面,申请 DNS 证书前不需要先创建任何 Proxy Host,也不要求 Host 开放 HTTP 访问——这对内网服务、尚未上线的新站点、以及源站位于 CDN 之后的场景非常友好。

前置条件:准备 DNS Provider 的 API 凭证

要使用 DNS 验证,你必须拥有 DNS 托管服务商的 API 凭证(Token / Secret / Access Key 等),并在 NPM 界面中正确填写。仓库 dns-plugins.json 内置了大量提供商的支持定义,例如:

# Cloudflare dns_cloudflare_api_token=0123456789abcdef0123456789abcdef01234567 # Aliyun dns_aliyun_access_key = 12345678 dns_aliyun_access_key_secret = 1234567890abcdef1234567890abcdef # DNSPod dns_dnspod_email = "email@example.com" dns_dnspod_api_token = "id,key" # DigitalOcean dns_digitalocean_token = 0000111122223333444455556666777788889999aaaabbbbccccddddeeeeffff # Namecheap dns_namecheap_username = 123456 dns_namecheap_api_key = 0123456789abcdef0123456789abcdef01234567

不同插件要求的字段完全不同(如 Google 需要 JSON 格式的服务账号、Azure 需要 SP/MSI 认证信息、RFC 2136 需要 TSIG 密钥),创建前请先确认你的 DNS 服务商是否在清单中,并按该插件要求的格式填写凭证。凭证填写后保存在meta.dns_provider_credentials中,API 返回给前端时会被过滤(见 internal/certificate.js 的omissions定义),避免敏感信息泄露。

操作步骤

  1. 进入Certificates页面,点击Add SSL Certificate,选择Let's Encrypt Certificate(DNS Challenge)
  2. 在 DNSCertificateModal 中填写域名。由于 DNS 验证支持通配符,这里允许输入*.example.com
  3. 选择密钥类型(Key Type)
  4. 在 DNS Provider 字段中选择你的服务商,并按模板粘贴对应凭证(见 DNSProviderFields);
  5. 点击Save保存并触发签发。

重要特性:支持 Wildcard 通配符

与 HTTP 验证不同,DNS 验证过程支持通配符域名。这也是生产环境中申请*.example.com证书的标准路径。签发完成后,该证书既可用于example.com根域名,也可覆盖*.example.com的所有子域名。

自定义证书(Custom Certificate)

适用场景

当你已经持有由自有 CA(证书颁发机构)签发的 SSL 证书时(例如企业内部的 PKI 证书、付费商业证书、或由其他 ACME 客户端签发的证书),可以使用Custom方式直接上传,NPM 不参与签发流程。

上传的三个文件

在 CustomCertificateModal 中,需要提供:

字段说明是否必填
证书(Certificate)站点证书主体(PEM 格式)
证书密钥(Certificate Key)与证书配对的私钥(PEM 格式)
中间证书(Intermediate Certificate)证书链中的中间 CA 证书否(建议填写以保证完整信任链)

保存前的三步校验

前端在提交时并非直接保存,而是经历"先校验、再建记录、再上传"三步(对应 CustomCertificateModal.tsx 的onSubmit):

  1. 校验(validate):调用POST /api/nginx/certificates/validate,后端 validate 方法 会分别对私钥执行openssl pkey -check校验(见 checkPrivateKey),对证书执行openssl x509解析(见 getCertificateInfo),并检查证书是否已过期(throwExpired参数)——过期证书会被直接拒绝;
  2. 创建(create):以provider: "other"创建一条证书记录;
  3. 上传(upload):将证书文件内容写入数据库,并由 writeCustomCert 写入磁盘目录/data/custom_ssl/npm-<certificate_id>/,生成fullchain.pem(自动拼接中间证书)与privkey.pem

上传时后端会通过allowedSslFiles白名单(certificatecertificate_keyintermediate_certificate)过滤文件,防止无关内容混入(见 upload 方法)。

证书生命周期管理:续期、下载与删除

无论通过哪种方式创建,证书都具备完整的生命周期管理能力,对应后端 API 路由定义于 routes/nginx/certificates.js。

自动续期:到期前 30 天

Nginx Proxy Manager 内置了一个自动续期定时器(initTimer / processExpiringHosts):

  • 1 小时检查一次所有provider = letsencrypt且未删除的证书;
  • 凡是expires_on30 天内到期的证书,都会触发自动续期(renewBeforeExpirationBy = [30, "days"]);
  • 续期任务必须串行执行(按证书逐个排队),因为 certbot 不允许两个实例并发运行(源码注释明确提示Another instance of Certbot is already running错误)。

续期成功后,后端会从磁盘上的fullchain.pem重新解析到期时间并更新数据库(见 renew 方法)。需要说明的是:自动续期仅适用于 Let's Encrypt 证书,自定义证书需要你自行在 CA 侧处理续期。

手动续期与下载

  • Renew:在证书列表中对 Let's Encrypt 证书点击续期,调用POST /api/nginx/certificates/:id/renew。由于 ACME 挑战可能耗时较长,路由设置了15 分钟超时req.setTimeout(900000)),创建证书的接口同样适用。
  • Download:Let's Encrypt 证书支持打包下载(GET /api/nginx/certificates/:id/download)。后端会将/etc/letsencrypt/live/npm-<id>/下的.pem文件打包为npm-<id>-<时间戳>.zip(见 download / zipFiles)。自定义证书不支持下载(接口会抛出Only Let'sEncrypt certificates can be downloaded)。

删除与吊销

删除证书时,如果是 Let's Encrypt 证书,后端会同步调用certbot revoke --delete-after-revoke执行吊销(见 revokeLetsEncryptSsl),并清理对应的 DNS 凭证文件;删除操作本身是软删除(is_deleted = 1),见 delete 方法。

密钥类型(Key Type)与元数据

创建 Let's Encrypt 证书时,前端表单会提供Key Type选项(rsa/ecdsa,默认ecdsa)。该值保存在meta.key_type中,后端组装 certbot 命令时会追加--key-type <type>参数(见 requestLetsEncryptSsl 与 requestLetsEncryptSslWithDnsChallenge)。key_type的合法取值在 certificate-object.json 中枚举为["rsa", "ecdsa"]。生产环境建议:

  • 需要与旧客户端(如老 Android 设备)兼容时选择rsa
  • 追求更小的握手开销、现代客户端环境选择ecdsa

meta对象是证书扩展信息的核心容器,支持的字段包括(见 certificate-object.json):

字段类型说明
certificate/certificate_key/intermediate_certificatestring自定义证书的 PEM 内容
dns_challengeboolean是否为 DNS 验证方式
dns_providerstringDNS 插件标识(对应 dns-plugins.json 的 key)
dns_provider_credentialsstringDNS 插件凭证(API 返回时被过滤)
propagation_secondsintegerDNS 记录传播等待秒数
key_typeenumrsa/ecdsa
letsencrypt_certificateobject签发后回填的证书信息(CN、issuer、有效期)

常见问题排查(FAQ)

HTTP 验证失败怎么办?

按 HTTPCertificateModal 的预检结果逐项排查:

  • no-host:域名 A 记录未解析到本机公网 IP,检查 DNS;
  • 404:80 端口可访问但路径不对,确认 Proxy Host 指向本机且未覆盖 ACME 挑战目录;
  • wrong-data:返回内容非预期令牌,可能存在其他服务抢占了/路径或反向代理规则未生效;
  • failed / other:临时网络故障,稍后重试或检查防火墙。

另外确认:申请域名对应的 Proxy Host 必须保留 HTTP(80)访问;如果使用了 CDN 或强制跳转 HTTPS 的规则,ACME 挑战可能被拦截。

DNS 验证失败怎么办?

  • 确认 DNS 凭证格式与 dns-plugins.json 中该插件的credentials模板完全一致;
  • 确认 API 账号具备新增/删除 TXT 记录的权限;
  • 若你的 DNS 服务商解析生效较慢,可适当调大propagation_seconds(等待传播后再让 Let's Encrypt 查询);
  • 检查插件是否已安装:NPM 会在请求时自动安装(installPlugin),安装失败会直接导致签发失败。

证书续期失败?

  • 对于 HTTP 验证证书:检查对应 Proxy Host 是否仍开放 80 端口 HTTP 访问;
  • 对于 DNS 验证证书:检查 DNS 凭证是否仍有效(凭证过期/轮换后需重新保存证书配置);
  • 查看容器内日志目录/data/logs/(certbot 日志位于--logs-dir /data/logs,另见 letsencrypt-request.conf 中的access_log/error_log配置)确认 certbot 具体报错。

总结

Nginx Proxy Manager 的证书模块通过"HTTP 验证、DNS 验证、自定义证书"三种路径,覆盖了从入门到生产环境的全部证书需求:HTTP 验证最简单,但要求先有公网可达的 Proxy Host 且不支持通配符;DNS 验证多一步插件凭证配置,但换来通配符支持与更强的部署灵活性;自定义证书则完全托管外部 CA 签发的证书。理解这三种方案背后的 ACME 挑战原理(结合 internal/certificate.js 中 certbot 命令的组装逻辑),能让你在配置与排障时游刃有余。

【免费下载链接】nginx-proxy-managerDocker container for managing Nginx proxy hosts with a simple, powerful interface项目地址: https://gitcode.com/GitHub_Trending/ng/nginx-proxy-manager

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

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/9/10 1:32:50

两周自学的理论全废:特征存储让我重新报了AI入门课

两周自学的理论全废:特征存储让我重新报了AI入门课 我在后端写了四年 Java,今年年初决定转 AI,照着网上最火的路线图刷了两周视频和教材:吴恩达的机器学习课、西瓜书前五章、PyTorch 官方教程。那两周我每天上下班地铁都挂着耳机,笔记记了满满一个 Notion。周末拿出一个信用卡…

作者头像 李华
网站建设 2026/9/10 1:32:40

Sourcetrail:半小时摸清一个陌生代码库的依赖结构

Sourcetrail&#xff1a;半小时摸清一个陌生代码库的依赖结构 【免费下载链接】Sourcetrail Sourcetrail - free and open-source interactive source explorer 项目地址: https://gitcode.com/GitHub_Trending/so/Sourcetrail 接手一个陌生的代码库&#xff0c;最先卡住…

作者头像 李华
网站建设 2026/9/10 1:30:48

图片无损压缩实战:从4MB到400KB的免费工具与参数详解

做图这行干久了&#xff0c;你会发现一个特别魔幻的现实&#xff1a;拍出来一张5MB的照片&#xff0c;传到网页上显示出来大概也就占几百KB的屏&#xff0c;剩下的全在暗处烧你的流量和服务器带宽。尤其是做电商、做新媒体、搞个人博客的朋友&#xff0c;图片体积控制不好&…

作者头像 李华
网站建设 2026/9/10 1:29:34

微信小程序阅读网站管理系统全栈开发实战解析

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

作者头像 李华