对于任何负责保障线上服务稳定与安全的系统而言,SSL/TLS 证书的管理是一项至关重要但又充满挑战的常规任务。它不仅是技术实践,更直接关系到用户信任和数据安全。随着 NGINX 官方发布 ngx_http_acme_module 模块,我们正迎来一次 TLS 证书管理范式的根本性变革,推动其向着更可靠、更安全、配置即代码(IaC)的理想状态发展。
在探讨 NGINX 的原生方案之前,我们有必要回顾长久以来行业内获取和管理 SSL/TLS 证书的两条主流路径:
Certbot + Cron 定时任务的组合虽然广泛应用,但其架构带来了新的运维挑战:
nginx.conf)与证书管理(脚本)分离,违反了“唯一真实来源”原则,增加了人为错误的风险。ACME 协议通过一系列“挑战-响应”测试来验证域名所有权。理解这些挑战是理解其自动化原理的关键。
1. HTTP-01 挑战(核心方式)
这是最普遍的验证方式,也是 NGINX ACME 模块目前支持的方式。其流程可以概括为:CA 向 ACME 客户端(现在是 NGINX)提供一个唯一的“令牌”,并要求客户端将这个令牌内容放置在一个约定好的 URL 路径下(/.well-known/acme-challenge/)。随后,CA 从公网访问该 URL,如果能获取到预期的内容,即证明客户端对该 Web 服务器拥有控制权。这种方式简单直接,完美契合 Web 服务器的本职工作,但前提是服务器的 80 端口必须对公网开放。
2. 其他验证方式(暂不支持,仅作说明)
需要明确的是,NGINX ACME 模块在当前版本中专注于 HTTP-01 挑战,暂不支持以下两种验证方式。在此介绍它们,是为了提供一个更完整的 ACME 协议背景知识。
*.example.com),并且服务器无需暴露于公网。NGINX 的原生方案选择了最适合其自身角色的 HTTP-01 挑战,将验证流程无缝集成到了请求处理中,从而实现了前所未有的简洁与高效。
与许多 NGINX 模块一样,ngx_http_acme_module 是一个动态模块,需要手动编译并加载到您的 NGINX 中。对于 NGINX Plus 用户,可以直接从官方仓库获取。对于广大的 NGINX Open Source 用户,以下是标准的编译安装步骤。
版本要求与兼容性
在开始之前,最重要的一点是理解版本兼容性。nginx-acme 模块及其底层的 ngx-rust SDK 是非常新的技术,它们依赖 NGINX 核心中新增的函数接口(API)。
not found in nginx_sys 等错误而失败。1.26+ 系列的所有关于tls相关的优化功能,并进入了以修复 bug 为主的稳定维护周期,是生产环境的最佳选择。第一步:准备编译环境
由于该模块是基于 Rust 开发的,您的编译环境除了需要常规的 C 编译器和 NGINX 依赖库外,还必须安装 Rust 工具链。
# 在 Debian/Ubuntu 系统上安装基础编译工具和 NGINX 依赖
$ sudo apt update
$ sudo apt install build-essential libpcre3-dev zlib1g-dev libssl-dev pkg-config libclang-dev git -y
# 安装 Rust 工具链 (cargo 和 rustc)
$ curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh
$ source $HOME/.cargo/env第二步:获取 NGINX 和 ACME 模块的源码
您需要下载与您当前运行版本相匹配的 NGINX 源码,以及 ACME 模块的源码。
$ mkdir -pv /app/nginx/{logs,conf,cache, acme} /app/nginx-build
$ cd /app/nginx-build
# 克隆 ACME 模块的源码
$ git clone https://github.com/nginx/nginx-acme.git /app/nginx-build/nginx-acme
# 或者
# git clone git@github.com:nginx/nginx-acme.git /app/nginx-build/nginx-acme
# 下载 NGINX 源码(请替换为您需要的版本)
wget https://nginx.org/download/nginx-1.28.0.tar.gz
tar -zxf nginx-1.28.0.tar.gz第三步:编译动态模块
进入 NGINX 源码目录,运行 ./configure 脚本,并使用 --add-dynamic-module 参数指向 ACME 模块的源码路径。这里是基于debian官方仓库的nginx构建参数反解析拿来的编译参数,因人而异,自行调整。
$ cd nginx-1.28.0
$ ./configure \
--prefix=/app/nginx \
--error-log-path=/app/nginx/error.log \
--http-log-path=/app/nginx/access.log \
--pid-path=/app/nginx/nginx.pid \
--lock-path=/app/nginx/nginx.lock \
--http-client-body-temp-path=/app/nginx/cache/client_temp \
--http-proxy-temp-path=/app/nginx/cache/proxy_temp \
--http-fastcgi-temp-path=/app/nginx/cache/fastcgi_temp \
--http-uwsgi-temp-path=/app/nginx/cache/uwsgi_temp \
--http-scgi-temp-path=/app/nginx/cache/scgi_temp \
--user=nginx \
--group=nginx \
--with-compat \
--with-file-aio \
--with-threads \
--with-http_addition_module \
--with-http_auth_request_module \
--with-http_dav_module \
--with-http_flv_module \
--with-http_gunzip_module \
--with-http_gzip_static_module \
--with-http_mp4_module \
--with-http_random_index_module \
--with-http_realip_module \
--with-http_secure_link_module \
--with-http_slice_module \
--with-http_ssl_module \
--with-http_stub_status_module \
--with-http_sub_module \
--with-http_v2_module \
--with-http_v3_module \
--with-mail \
--with-mail_ssl_module \
--with-stream \
--with-stream_realip_module \
--with-stream_ssl_module \
--with-stream_ssl_preread_module \
--with-cc-opt='-g -O2 -ffile-prefix-map=/home/builder/debuild/nginx-1.28.0/debian/debuild-base/nginx-1.28.0=. -fstack-protector-strong -Wformat -Werror=format-security -Wp,-D_FORTIFY_SOURCE=2 -fPIC' \
--with-ld-opt='-Wl,-z,relro -Wl,-z,now -Wl,--as-needed -pie' \
--add-dynamic-module=/app/nginx-build/nginx-acme
$ make && \
make modules && \
make install
# 运行配置脚本,这里的关键是 --add-dynamic-module
# 注意:您需要在这里包含您当前 NGINX 已有的所有编译参数,可以通过 nginx -V 查看
# 编译模块,注意是 make modules 而不是 make install第四步:安装并加载模块
编译成功后,会在 objs 目录下生成一个 .so 文件,您需要将其复制到 NGINX 的模块目录。如果执行的如上make install 则不需要手动copy。
这里个给出一个完整可以运行的 nginx.conf 文件:
# /app/nginx/conf/nginx.conf
user nginx;
error_log error.log debug;
pid nginx.pid;
load_module modules/ngx_http_acme_module.so;
events {
worker_connections 1024;
multi_accept on;
}
http {
include mime.types;
default_type application/octet-stream;
log_format main '$remote_addr - $remote_user [$time_local] "$host" "$request" '
'$status $body_bytes_sent "$http_referer" '
'"$http_user_agent" "$http_x_forwarded_for"';
access_log access.log main;
sendfile on;
tcp_nopush on;
charset utf-8;
keepalive_timeout 65;
gzip on;
resolver 8.8.8.8 1.1.1.1;
acme_issuer letsencrypt {
uri https://acme-v02.api.letsencrypt.org/directory;
contact mailto:security-alerts@aidig.co;
state_path acme/letsencrypt;
accept_terms_of_service;
}
acme_shared_zone zone=acme_shared:1M;
server {
listen 443 ssl;
server_name ssl.aidig.co;
acme_certificate letsencrypt;
ssl_certificate $acme_certificate;
ssl_certificate_key $acme_certificate_key;
ssl_certificate_cache max=2; # required ngx 1.27.4+
location / {
default_type text/plain;
return 200 'OK';
}
}
server {
listen 80 default_server;
server_name _;
location / {
return 301 https://$host$request_uri;
}
}
}完成以上步骤并重启 NGINX 后,ACME 模块就成功加载并准备就绪了。
# 验证配置文件语法
$ cd /app/nginx/
$ ./sbin/nginx -c conf/nginx.conf -t
# 启动
$ ./sbin/nginx -c conf/nginx.conf
# 配置变更后重载
$ ./sbin/nginx -c conf/nginx.conf -s reload第五步:功能验证
这里就直接放一些验证的截图了,不做过多赘述。



在展示 ACME 模块的具体配置前,必须强调一点:一个生产环境的完整 HTTPS 配置,还应包含一系列用于提升性能和安全性的 TLS 优化指令。例如 ssl_session_cache、ssl_session_timeout 用于启用会话复用以降低连接延迟,ssl_protocols 和 ssl_ciphers 用于定义支持的安全协议和加密套件等。
为确保本文聚焦于核心主题,我们将不会对这些 TLS 优化指令展开详细讨论。 下文展示的配置将仅包含实现 ACME 自动化功能所必需的最小化设置。
整个流程被简化为纯粹的 NGINX 配置指令,直观且强大。
1. 定义 ACME 颁发机构 (acme_issuer)
http {
resolver 127.0.0.1:53;
# 可选指令 acme_shared_zone,用于存储所有配置的证书颁发者的证书、私钥和挑战数据。该区域默认大小为 256K,可根据需要增加
acme_shared_zone zone=acme_shared:1M;
# 定义一个名为 letsencrypt_prod 的 ACME 颁发机构实例
acme_issuer letsencrypt {
# 指定 ACME 服务提供商的目录 URL,这里是 Let's Encrypt 的生产环境
uri https://acme-v02.api.letsencrypt.org/directory;
# 提供一个联系邮箱,用于接收 CA 的重要通知(如证书即将过期)
contact mailto:security-alerts@example.com;
# 同意服务条款,对于 Let's Encrypt 等 CA 这是必需的步骤
accept_terms_of_service;
# 指定状态文件的存储路径,用于保存 ACME 账户密钥,非常重要
state_path acme/letsencrypt;
}
}2. 在 Server 块中声明并应用 ACME 证书
在一个需要启用 HTTPS 的 server 块中,我们通过 acme_certificate 指令来“声明”证书需求,并立刻使用模块提供的动态变量来“应用”它。
server {
listen 443 ssl;
server_name www.example.com;
# 步骤一:声明此 server 块启用 ACME,并指定使用上面定义的 letsencrypt_prod 颁发机构
acme_certificate letsencrypt;
# 步骤二:使用动态变量加载由 ACME 模块在内存中管理的证书和私钥
ssl_certificate $acme_certificate;
ssl_certificate_key $acme_certificate_key;
ssl_certificate_cache max=2; # ngx 1.27.4+
location / {
default_type text/plain;
return 200 'OK';
}
}4. 配置 HTTP-01 挑战的响应端点
server {
# 监听 80 端口并设置为默认服务器,用于捕获所有 HTTP 请求
listen 80 default_server;
# 使用一个无效主机名来匹配所有未被其他 server 块精确匹配的域名
server_name _;
# ACME 模块会自动处理 /.well-known/acme-challenge/ 的请求,此 location 用于处理所有其他请求
location / {
# 将所有非 ACME 验证的 HTTP 流量强制重定向到 HTTPS
return 301 https://$host$request_uri;
}
}NGINX 原生 ACME 支持的引入,标志着 TLS 自动化管理的一次重大进步。它不再是已有工作流的增量改进,而是一次彻底的范式转移,通过将证书管理从一个脆弱的外部依赖(如 Certbot 和 Cron)转变为 NGINX 自身的核心能力,精准地解决了传统模式下的诸多痛点。
这种深度集成的方式,首先带来了运维可靠性的质变。通过用 NGINX 成熟的事件循环取代不可靠的定时任务,系统告别了“静默失败”的风险。其次,它实现了配置的真正统一。将证书生命周期管理指令直接写入 nginx.conf,使之成为唯一的真实来源,完美契合了基础设施即代码(IaC)的核心理念,消除了配置与执行的分裂。最后,在安全性上,整个流程在 NGINX 标准工作进程的低权限下运行,避免了不必要的提权操作,收敛了系统的攻击面。
对于追求高度自动化、稳定可靠的现代网络架构而言,这无疑是一次意义深远的技术演进,它让基础设施向着真正的“配置即一切”迈出了坚实的一步。
info 09/06/2025 update:增加Nginx ACME 自动编译构建工作流,每天早晨自动检查,是否需要根据nginx新版本编译对应nginx acme 适配模块。
https://github.com/hzbd/nginx-acme-build
Ref:
原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。
如有侵权,请联系 cloudcommunity@tencent.com 删除。
原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。
如有侵权,请联系 cloudcommunity@tencent.com 删除。