Puppet部署Let's Encrypt证书失败致Nginx启动异常求助
错误现象
执行puppet agent -t --no-noop时出现以下错误:
Error: Could not set 'file' on ensure: No such file or directory @ rb_sysopen - /etc/letsencrypt/live/test.domain.com/cert.pem (file: /etc/puppetlabs/code/environments/production/site/profiles/manifests/letsencrypt.pp, line: 27) Error: Could not set 'file' on ensure: No such file or directory @ rb_sysopen - /etc/letsencrypt/live/test.domain.com/cert.pem (file: /etc/puppetlabs/code/environments/production/site/profiles/manifests/letsencrypt.pp, line: 27) Wrapped exception: No such file or directory @ rb_sysopen - /etc/letsencrypt/live/test.domain.com/cert.pem Error: /Stage[main]/Profiles::Letsencrypt/File[/etc/letsencrypt/live.test.evolvedbinary.com/cert.pem]/ensure: change from 'absent' to 'file' failed: Could not set 'file' on ensure: No such file or directory @ rb_sysopen - /etc/letsencrypt/live/test.domain.com/cert.pem (file: /etc/puppetlabs/code/environments/production/site/profiles/manifests/letsencrypt.pp, line: 27)
该错误导致Nginx启动失败,日志如下:
Error: Systemd start for nginx failed! journalctl log for nginx: -- Logs begin at Fri 2023-08-18 12:11:49 BST, end at Thu 2023-09-07 12:08:25 BST. -- Sep 07 12:08:25 test-web systemd[1]: Starting nginx - high performance web server... Sep 07 12:08:25 test-web nginx[312617]: nginx: [emerg] cannot load certificate \"/etc/letsencrypt/live/test.domain.com/cert.pem\": BIO_new_file() failed
排查过程
- 确认
/etc/letsencrypt/live/test.domain.com/cert.pem文件未生成是核心问题 - 在Puppet的
letsencrypt.pp中给cert.pem的file资源添加force => true参数,问题未解决 - 在Agent节点手动用vim创建空白cert.pem文件后,执行Puppet命令仍报错
相关配置文件
letsencrypt.pp
class profiles::letsencrypt { package { 'cron': ensure => installed } class { 'letsencrypt': require => Package['cron'] } file { '/etc/letsencrypt/options-ssl-nginx.conf': ensure => file, } file {'/etc/letsencrypt/ssl-dhparams.pem': ensure => file, } file {'/etc/letsencrypt/live': ensure => directory, } file {'/etc/letsencrypt/live/test.domain.com': ensure => directory, } file {'/etc/letsencrypt/live/test.domain.com/cert.pem': ensure => file, } include 'letsencrypt' include 'letsencrypt::plugin::dns_cloudflare' # include 'letsencrypt::plugin::nginx' letsencrypt::certonly { '*.test.domain.com': domains => ['*.test.domain.com'], plugin => 'dns-cloudflare', manage_cron => true, cron_hour => [0,12], cron_minute => '30', cron_before_command => 'service nginx stop', cron_success_command => '/bin/systemctl reload nginx.service', #suppress_cron_output => true, require => Class['nginx'], } }
test-web.domain.com.yaml
--- classes: - roles::www # UFW Rules ufw::rules: 'Allow HTTP': action: allow to_ports_app: 80 proto: tcp 'Allow HTTPS': action: allow to_ports_app: 443 proto: tcp # nginx rules nginx::nginx_servers: 'www.test.domain.com': server_name: [ '*.test.domain.com', 'test.domain.com', ] ipv6_enable: true ssl: true http2: 'on' ssl_redirect: true ssl_cert: '/etc/letsencrypt/live/test.domain.com/cert.pem' ssl_key: '/etc/letsencrypt/live/test.domain.com/privkey.pem' www_root: '/var/www/www.test.domain.com' server_cfg_ssl_append: include: '/etc/letsencrypt/options-ssl-nginx.conf' ssl_dhparam: '/etc/letsencrypt/ssl-dhparams.pem' # letsencrypt letsencrypt::email: 'sysops@domain.com' letsencrypt::plugin::dns_cloudflare::email: 'user.@email.com'
解决方案
删除手动创建证书的Puppet资源:移除
letsencrypt.pp中file {'/etc/letsencrypt/live/test.domain.com/cert.pem': ensure => file,}这一段。证书应由letsencrypt::certonly自动生成,手动创建空文件会干扰证书生成流程,还可能引发权限问题。修复循环依赖问题:当前
letsencrypt::certonly依赖Nginx,但Nginx配置又依赖证书,形成循环。调整依赖关系,让Nginx服务器配置依赖证书生成完成:
在Puppet的Nginx服务器定义中添加require => Letsencrypt::Certonly['*.test.domain.com'],确保证书生成后再配置启动Nginx。验证Cloudflare插件配置:确认Cloudflare的API密钥已正确配置(需在Hiera中添加
letsencrypt::plugin::dns_cloudflare::api_key: '你的API密钥'),并确保凭据文件权限为600、属主为root,DNS验证失败会直接导致证书无法生成。手动触发证书生成(临时修复):在Agent节点执行以下命令手动生成证书,验证流程是否正常:
certbot certonly --dns-cloudflare --dns-cloudflare-credentials /etc/letsencrypt/cloudflare.ini -d *.test.domain.com清理重复的Letsencrypt声明:
letsencrypt.pp中同时使用了class { 'letsencrypt': }和include 'letsencrypt',保留其中一种即可,推荐保留class { 'letsencrypt': }来统一管理参数,避免重复声明冲突。
内容的提问来源于stack exchange,提问作者Callum McCrorie

