LOGO OA教程 ERP教程 模切知识交流 PMS教程 CRM教程 开发文档 其他文档  
 
网站管理员

[点晴永久免费OA]NGINX 原生 ACME 支持:从根本上重塑 https 协议 SSL/TLS 证书自动化部署

admin
2025年8月28日 0:50 本文热度 16

对于任何负责保障线上服务稳定与安全的系统而言,SSL/TLS 证书的管理是一项至关重要但又充满挑战的常规任务。它不仅是技术实践,更直接关系到用户信任和数据安全。随着 NGINX 官方发布 ngx_http_acme_module 模块,我们正迎来一次 TLS 证书管理范式的根本性变革,推动其向着更可靠、更安全、配置即代码(IaC)的理想状态发展。

背景:SSL/TLS 证书管理的演进之路

在探讨 NGINX 的原生方案之前,我们有必要回顾长久以来行业内获取和管理 SSL/TLS 证书的两条主流路径:

  1. 1. 传统商业证书路径:这是最早期也是最经典的方式。企业或个人向 Verisign、GeoTrust 等大型证书颁发机构(CA)付费购买 SSL 证书。这个过程通常涉及手动生成证书签名请求(CSR)、通过邮件或 DNS 记录验证域名所有权、支付费用,最后将获取到的证书文件手动部署到服务器上。这种方式的主要痛点在于:成本高昂,尤其是对于拥有大量域名的场景;流程繁琐,人为操作环节多,容易出错;更新困难,证书到期前需要人工跟进,一旦疏忽将导致服务中断。
  2. 2. Certbot 与免费证书的兴起:为了推动全网加密,Let's Encrypt 项目应运而生,它通过 ACME 协议提供免费、自动化的证书签发服务。Certbot 作为 ACME 协议最知名的客户端工具,迅速普及开来。它极大地降低了使用 SSL 的门槛,使得个人开发者和中小型企业也能轻松启用 HTTPS。这条路径是自动化的一大步,但它并非银弹,而是将挑战从“获取”转移到了“维护自动化工具”上。

传统自动化方案(Certbot)的挑战

Certbot + Cron 定时任务的组合虽然广泛应用,但其架构带来了新的运维挑战:

  • • 脆弱的外部依赖:Certbot 依赖于特定的运行时环境(如 Python),系统更新或应用间的依赖冲突可能导致其失效。
  • • 不可靠的定时任务:基于 Cron 的脚本在执行失败时容易“静默”,缺乏直观的监控和告警,往往直到证书过期才发现问题。
  • • 配置与执行的分裂:服务配置(nginx.conf)与证书管理(脚本)分离,违反了“唯一真实来源”原则,增加了人为错误的风险。
  • • 权限管理的难题:为实现自动化,脚本通常需要较高的系统权限,这带来了潜在的安全隐患。

ACME 核心机制:证明域名所有权的挑战

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 协议背景知识。

  • • DNS-01 挑战:此方式不依赖 Web 服务器,而是通过在域名的 DNS 设置中添加一条特定的 TXT 记录来完成验证。它的主要优势在于支持申请通配符证书(如 *.example.com),并且服务器无需暴露于公网。
  • • TLS-ALPN-01 挑战:这是一种更特殊的方式,它通过 TLS 协议本身来完成验证,优点是不占用 80 端口。不过,它的应用场景相对较少,普及度不如前两者。

NGINX ACME 模块:架构层面的解决方案

NGINX 的原生方案选择了最适合其自身角色的 HTTP-01 挑战,将验证流程无缝集成到了请求处理中,从而实现了前所未有的简洁与高效。

如何安装 NGINX ACME 模块

与许多 NGINX 模块一样,ngx_http_acme_module 是一个动态模块,需要手动编译并加载到您的 NGINX 中。对于 NGINX Plus 用户,可以直接从官方仓库获取。对于广大的 NGINX Open Source 用户,以下是标准的编译安装步骤。

版本要求与兼容性
在开始之前,最重要的一点是理解版本兼容性。nginx-acme 模块及其底层的 ngx-rust SDK 是非常新的技术,它们依赖 NGINX 核心中新增的函数接口(API)。

  • • 最低版本要求:NGINX 1.25.1。任何低于此版本的 NGINX(如 1.24.x, 1.22.x)都缺少必要的 API,会导致编译时出现 not found in nginx_sys 等错误而失败。
  • • 生产环境推荐:NGINX 1.28.0 或更高的稳定(Stable)版本。该版本继承了 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 模块的源码路径。

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_logerror.log  debug;
pid        nginx.pid;

load_module modules/ngx_http_acme_module.so;

events {
    worker_connections1024;
    multi_accepton;
}

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_timeout65;
    gzipon;

    resolver8.8.8.81.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 {
        listen443 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;
            return200'OK';
        }
    }

    server {
        listen80 default_server;
        server_name _;

        location / {
            return301 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

第五步:功能验证

这里就直接放一些验证的截图了,不做过多赘述。



Ngx-ACME 核心工作机制与配置详解

在展示 ACME 模块的具体配置前,必须强调一点:一个生产环境的完整 HTTPS 配置,还应包含一系列用于提升性能和安全性的 TLS 优化指令。例如 ssl_session_cache、ssl_session_timeout 用于启用会话复用以降低连接延迟,ssl_protocols 和 ssl_ciphers 用于定义支持的安全协议和加密套件等。

为确保本文聚焦于核心主题,我们将不会对这些 TLS 优化指令展开详细讨论。 下文展示的配置将仅包含实现 ACME 自动化功能所必需的最小化设置。

整个流程被简化为纯粹的 NGINX 配置指令,直观且强大。

1. 定义 ACME 颁发机构 (acme_issuer)

http {
    resolver127.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 {
    listen443 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;
        return200'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 标准工作进程的低权限下运行,避免了不必要的提权操作,收敛了系统的攻击面。

对于追求高度自动化、稳定可靠的现代网络架构而言,这无疑是一次意义深远的技术演进,它让基础设施向着真正的“配置即一切”迈出了坚实的一步。

Ref:

https://nginx.org/en/linux_packages.html
https://github.com/nginx/nginx-acme
https://github.com/nginx/nginx-acme/blob/main/.github/workflows/ci.yaml#L50
https://nginx.org/en/docs/http/ngx_http_acme_module.html
https://blog.nginx.org/blog/native-support-for-acme-protocol
https://www.rfc-editor.org/rfc/rfc8555.html


阅读原文:原文链接


该文章在 2025/8/28 16:50:31 编辑过
关键字查询
相关文章
正在查询...
点晴ERP是一款针对中小制造业的专业生产管理软件系统,系统成熟度和易用性得到了国内大量中小企业的青睐。
点晴PMS码头管理系统主要针对港口码头集装箱与散货日常运作、调度、堆场、车队、财务费用、相关报表等业务管理,结合码头的业务特点,围绕调度、堆场作业而开发的。集技术的先进性、管理的有效性于一体,是物流码头及其他港口类企业的高效ERP管理信息系统。
点晴WMS仓储管理系统提供了货物产品管理,销售管理,采购管理,仓储管理,仓库管理,保质期管理,货位管理,库位管理,生产管理,WMS管理系统,标签打印,条形码,二维码管理,批号管理软件。
点晴免费OA是一款软件和通用服务都免费,不限功能、不限时间、不限用户的免费OA协同办公管理系统。
Copyright 2010-2025 ClickSun All Rights Reserved