如何将新的 SSL 证书和密钥注入 运行 节点 http.Server?

How can I inject a new SSL cert and key into a running Node http.Server?

我是 运行 TCP 服务的安全 websocket 代理。这使用标准 http.Server 设置如下:

var webserver = http.createServer(                                                                          
    {                                                                                                       
        key: fs.readFileSync(srv.ssl_key),                                                                  
        cert: fs.readFileSync(srv.ssl_cert),                                                                
    },                                                                                                      
    function(request, response) {                                                                           
        response.writeHead(404);                                                                            
        response.end();                                                                                     
    },                                                                                                      
    function(err) {                                                                                         
        srv.log(err);                                                                                       
    }                                                                                                       
);

如您所见,我们已经在使用 hilariously undocumented facilitieshttp.createServer() 的选项和错误处理程序参数。

SSL 密钥和证书由 LetsEncrypt certbot 定期重新生成。发生这种情况时,我想将新密钥和证书注入网络服务器,而不必重新生成新密钥和证书或重新初始化我的网络套接字。

还有什么未记录的设施可以让我这样做?

你必须:

  1. 关闭当前网络服务器 webserver.close()
  2. 使用您的新密钥和证书创建一个新的网络服务器实例(上面有一个 .setOptions() 方法,您可能认为您可以使用它来更改 keycert 选项,但无法让它在实例化后生成新的 TLS 凭据)
  3. 使用 websocketServer.mount(websocketOptions) 在 websocket 服务器上安装新的网络服务器,其中 websocketOptions.httpServer 是您的新网络服务器实例

这将工作得很好而且很顺利,不会干扰 运行 连接。

使用 SNICallback

实际上,您不应该提供 certkey,而应使用 SNICallback 代替它们。

(HTTPS 实际上只是 HTTP 和 TLS 的包装,因此最好直接查看 TLS 文档以了解任何处理证书的信息)

例如:

function getCerts(servername, cb) {
  cb(null, tls.createSecureContext({
    key: '...' // privkey.pem
  , cert: '...' // cert.pem + '\r\n' + chain.pem
  }));
}

http.createServer({ SNICallback: getCerts });

重要的是要注意错误被吞没并导致浏览器 tls 连接错误。如果您遇到错误情况,我强烈建议您在 cb(err) 之前先 console.error(err),因为无法捕获它或知道它是什么类型的错误。这是节点团队的故意决定。

Greenlock 会为您做这件事

这正是我对我编写的 ssl 证书管理器所做的,Greenlock.js and Greenlock for Express.js,它将:

  • 自动配置 SSL
  • 对于您允许的任何域都是动态的
  • 自动更新即将到期的证书
  • 热加载较新的证书
  • 存储插件可以处理自定义逻辑,因为它在发行或更新之前运行

它通过 ACME / Let's Encrypt 自动颁发证书,但是,如果您需要更自定义的解决方案,您可以覆盖默认存储插件以始终 return 证书,然后它甚至永远不会命中 ACME API.