如何在Node.js应用中实现Let's Encrypt SSL证书自动重载
解决Certbot更新SSL证书后自动重载Node.js应用的问题
我懂你的需求——每次Certbot自动更新SSL证书后,希望PM2管理的Node.js应用能自动加载新证书,不用手动操作对吧?下面给你两种可靠的方案,优先推荐第一种,简单又高效:
方案一:利用Certbot的部署钩子(推荐)
Certbot本身支持在成功更新证书后自动运行自定义脚本,我们可以用这个特性触发PM2重载应用,让Node.js重新读取新的证书文件。
步骤1:创建Certbot部署钩子脚本
在Certbot的钩子目录下创建一个可执行脚本,Certbot会在证书更新成功后自动执行它:
# 创建脚本文件 sudo nano /etc/letsencrypt/renewal-hooks/deploy/reload-pm2.sh
写入以下内容:
#!/bin/bash # 重载PM2中名为app.js的应用(如果你的PM2应用有自定义名称,替换成对应的名字) pm2 reload app.js
步骤2:给脚本添加执行权限
sudo chmod +x /etc/letsencrypt/renewal-hooks/deploy/reload-pm2.sh
步骤3:测试钩子是否生效
用Certbot的模拟更新命令测试,不会真的更新证书,但会触发钩子:
sudo certbot renew --dry-run
执行后查看PM2日志(pm2 logs),应该能看到应用被重载的记录,说明钩子生效了。
为什么这个方案可行?
你的Node.js应用是启动时一次性读取证书文件到内存的,证书更新后磁盘上的文件变了,但应用内存里还是旧的证书,必须重启/重载才能加载新的。PM2的reload是零停机重载,比直接restart更友好,用户不会感受到服务中断。
方案二:修改Node.js代码自动重载证书(进阶)
如果你不想依赖PM2的重载,也可以修改代码让应用定期检查证书文件变化,自动重新加载。这种方法适合不想重启应用的场景,但需要额外的代码开发:
修改你的Express应用代码:
var express = require('express'); var https = require('https'); var fs = require('fs'); const app = express(); app.use((req, res) => { res.end('Hello World'); }); // 定义加载证书的函数 function loadHttpsServer() { const options = { key: fs.readFileSync('/etc/letsencrypt/live/$DOMAIN/privkey.pem'), cert: fs.readFileSync('/etc/letsencrypt/live/$DOMAIN/fullchain.pem') }; // 如果之前有服务器实例,关闭旧的 if (global.httpsServer) { global.httpsServer.close(() => { console.log('旧HTTPS服务器已关闭,正在启动新服务器'); startHttpsServer(options); }); } else { startHttpsServer(options); } } function startHttpsServer(options) { global.httpsServer = https.createServer(options, app); global.httpsServer.listen(8000, () => { console.log('HTTPS服务器运行在端口8000'); }); } // 启动初始服务器 loadHttpsServer(); // 每12小时检查一次证书文件,自动重载(可根据需要调整间隔) setInterval(() => { console.log('检查证书是否需要更新...'); loadHttpsServer(); }, 12 * 60 * 60 * 1000);
这种方法会定期重新读取证书文件,关闭旧的HTTPS服务器并启动新的,实现证书热重载。但注意:这种方法可能会有极短的服务中断(比PM2 reload长一点),而且需要确保应用有足够的权限读取证书文件。
额外注意事项
- 权限问题:你的证书目录
/etc/letsencrypt/live/$DOMAIN/默认是root可读的,如果你用sudo pm2 start启动应用(root用户),那没问题;如果是普通用户启动PM2,需要给该用户添加读取证书目录的权限,比如用setfacl命令:sudo setfacl -R -m u:your_username:r /etc/letsencrypt/live/$DOMAIN/(比直接修改所有权更安全)。 - PM2应用名称:如果你的PM2应用有自定义名称(比如用
pm2 start app.js --name my-app),钩子脚本里要改成pm2 reload my-app。
内容的提问来源于stack exchange,提问作者Zain Ul Abideen




