-
Notifications
You must be signed in to change notification settings - Fork 29.8k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Reload certificate files of https.createServer() without restarting node server #15115
Comments
That's interesting. In practice, people solve this by running Node.js servers in a cluster of several instances, and then do a one-by-one update where severs individually go down and up with the new certificate so there is no runtime. WebSocket requests require "draining", so you stop routing connections to the server and then restart it once all the existing requests are done. I can see the use case here. |
FWIW you can already do this with const https = require('https');
const tls = require('tls');
const fs = require('fs');
var ctx = tls.createSecureContext({
key: fs.readFileSync(config.sslKeyPath),
cert: fs.readFileSync(config.sslCrtPath)
});
https.createServer({
SNICallback: (servername, cb) => {
// here you can even change up the `SecureContext`
// based on `servername` if you want
cb(null, ctx);
}
}); With that, all you have to do is re-assign |
@mscdex thank you for great working fallback (already implemented) :) |
@nolimitdev You should be able to still supply As far as overhead goes, it's just a couple of extra function calls really, I wouldn't be so worried about it. |
I wouldn't rule out non-SNI completely. There are still clients that don't support it or handle it inproperly, like the OpenSSL version included on the latest macOS ref. I think adding a method to update server options at runtime would be nice to have. Similar to what is possible for ticket keys using |
Duplicate of #4464? |
Yes, seems like a dupe. |
This commit adds a setSecureContext() method to TLS servers. In order to maintain backwards compatibility, the method takes the options needed to create a new SecureContext, rather than an instance of SecureContext. Fixes: nodejs#4464 Refs: nodejs#10349 Refs: nodejs/help#603 Refs: nodejs#15115 PR-URL: nodejs#23644 Reviewed-By: Ben Noordhuis <[email protected]>
This commit adds a setSecureContext() method to TLS servers. In order to maintain backwards compatibility, the method takes the options needed to create a new SecureContext, rather than an instance of SecureContext. Fixes: #4464 Refs: #10349 Refs: nodejs/help#603 Refs: #15115 PR-URL: #23644 Reviewed-By: Ben Noordhuis <[email protected]>
This commit adds a setSecureContext() method to TLS servers. In order to maintain backwards compatibility, the method takes the options needed to create a new SecureContext, rather than an instance of SecureContext. Fixes: nodejs#4464 Refs: nodejs#10349 Refs: nodejs/help#603 Refs: nodejs#15115 PR-URL: nodejs#23644 Reviewed-By: Ben Noordhuis <[email protected]>
SNICallback is only invoked once when the https server is created. As a result, SNICallback cannot be used to reload certificates. I couldn't find any API supported way of reloading certificates. |
I'm not sure where you get that from. The Lines 1054 to 1076 in 138eb32
|
I tried using it. Subsequent connections on the same domain do not go to SNICallback and so are using some kind of cache. NodeJS 11.7 |
It sounds like you're getting tripped up by TLS session resumption, either server-side (session IDs) or client-side (ticket keys.) It cuts short the TLS handshake but it means You can disable it (at the cost of reduced handshake performance) but you don't have to. Sessions resume from the key exchange step of the handshake, they don't look (and don't have to look) at the certificate. In other words, it's immaterial that https://hpbn.co/transport-layer-security-tls/#tls-session-resumption is the best overview I could find in 30 seconds of googling, hope that helps. :-) |
Thanks for taking the time to explain it to me. I’ll try with multiple clients and see how it goes. |
I was finally able to get this working without a full restart using tls.Server.setSecureContext. WebSocket connections using the old secure context remain open, while new WebSocket connections will use the fresh certificate. Time will tell if it works specifically with certbot, but I'm able to trigger a reload by overwriting the certificates with self-signed garbage (obviously back up the old ones first if you want to test). Oct 2023 update: See my followup below for code example |
@luisfonsivevo I think your implementation is unclear and complicated. Try to check this #4464 (comment) I do not use setSecureContext() because it was added in node v11 and my post is from january 2018 but you can use algorithm. I just used setTimeout()+clearTimeout() without needing sth. like your "reloading". You uselessly combined setTimeout() and "reloading". I also wrote there that it is useless to watch both private key and cert because when private key is changed also certificate must be changed, so vars "keyMod" and "certMod" are also useless. Maybe you should also use chokidar instead of native watch which is platform unreliable (I fixed possible problems by clearTimeout()). I use my algorithm for several years without problems. |
I think that hoping both certificates are finished writing to disk after 5 seconds would be unreliable. It's pretty unlikely to ever take longer, but still. I could definitely lose an |
So, to reload the certificate, can we use something like this code now? const wsServer = new ws.Server({ server: httpsServer });
httpsServer.listen(...);
setInterval(function() {
const privateKey = fs.readFileSync(keyPath, 'utf8');
const certificate = fs.readFileSync(crtPath, 'utf8');
const credentials = { key: privateKey, cert: certificate };
httpsServer.setSecureContext(credentials)
}, 1000 * 60 * 60 * 24); |
I've been using this for years now with no issue:
And here's a helper bash script to use it with certbot+letsencrypt (needs to run each time node.js is updated):
|
Im using much easier code base on watching file. @luisfonsivevo see For compatibility with old nodejs versions:
Nowadays setSecureContext can be used:
|
Hi, letsencrypt certificate files expires each 3 months. Is there any way to refresh certificate files without restarting node server? Because using stale/expired certificate causes error ERR_INSECURE_RESPONSE in browser.
No solution works and node always use stale certificate for new incoming https requests and websocket connections too . It would be great to have a new method in returned Object from https.createServer() to reload certificate files e.g.:
httpsServer.reloadCertificate({key: fs.readFileSync(config.sslKeyPath), cert: fs.readFileSync(config.sslCrtPath)})
... now, new incoming https requests or websocket connections should be handled with new certificate files
The text was updated successfully, but these errors were encountered: