Ansible 实现上百台 Nginx 服务器 SSL 证书自动更新的核心是构建可验证、可回滚、可监控的闭环流程,涵盖 ACME 申请、路径权限统一管理、安全重载(nginx -t && nginx -s reload)及备份/日志/告警三重保障,全部通过声明式控制收敛。

用 Ansible 实现上百台 Nginx 服务器 SSL 证书的定期自动更新,核心不是“写个脚本跑一遍”,而是构建一套可验证、可回滚、可监控的闭环流程。它不依赖人工盯日历,也不靠单点工具硬扛,关键在于把 ACME 申请、路径管理、Nginx 重载、异常兜底这四步全部纳入声明式控制。
统一证书生命周期管理
避免每台机器各自为政申请证书,统一由 Ansible 控制节点集中调度:
- 使用 acme-tiny 或 lego(轻量、无 Python 依赖)作为 ACME 客户端,通过 Ansible 的
command或shell模块调用 - 所有域名信息、联系邮箱、CA 地址(如 Let’s Encrypt 生产或 staging 环境)统一定义在 vars 文件或 group_vars 中,例如:
acme_domains: ["api.example.com", "www.example.com"]<br>acme_email: "ops@example.com"<br>acme_ca_url: "https://acme-v02.api.letsencrypt.org/directory"
- 证书有效期检查不靠 cron 猜测,而是每次执行前用
stat模块读取证书mtime,结合valid_to字段计算剩余天数,低于阈值(如 30 天)才触发续期
精准匹配 Nginx 配置路径与权限
证书更新失败,八成出在路径或权限错位。Ansible 必须显式收敛这两项:
- 在 Nginx server 块配置中,
ssl_certificate和ssl_certificate_key的路径必须与 Ansible 任务中copy模块的dest完全一致;建议统一存放在/etc/ssl/nginx/下,并用变量控制,例如:ssl_cert_path: "/etc/ssl/nginx/{{ item.domain }}.fullchain.pem"<br>ssl_key_path: "/etc/ssl/nginx/{{ item.domain }}.key" - 私钥权限必须为
0600,证书为0644;在 copy 任务后立即添加file模块修正:- name: Set strict permissions for private key<br> file:<br> path: "{{ ssl_key_path }}"<br> mode: '0600'<br> owner: root<br> group: root
安全重载 Nginx 而非重启
直接 systemctl restart nginx 可能导致短暂中断;应始终走 nginx -t && nginx -s reload 流程:
- 先用
command模块执行nginx -t校验配置语法,ignore_errors: yes并捕获返回码,失败则中断后续操作 - 校验通过后,再执行
nginx -s reload;不要用service模块,避免因 systemd 单元文件覆盖导致行为不一致 - 对多站点环境,可加
notify触发 handler,确保只在证书真正变更后才 reload,减少无效信号
备份 + 日志 + 异常告警三重保障
自动化不是放任不管,而是让问题暴露得更早、恢复得更快:
- 每次更新前,用
copy模块的backup: yes自动备份旧证书和私钥,保留时间戳后缀,路径可设为/etc/ssl/nginx/backup/ - 所有关键步骤(ACME 执行、文件拷贝、权限设置、reload)都启用
register并写入日志文件,例如:- name: Log certificate renewal<br> shell: echo "$(date): {{ ansible_hostname }} renewed {{ item.domain }}" >> /var/log/ansible/cert-renew.log<br> args:<br> executable: /bin/bash - 失败时通过
mail模块发告警(需提前配好 SMTP),或调用企业微信/钉钉 webhook;重点字段包括主机名、域名、错误输出、时间戳


















