使用 Express.js 的多个 SSL 证书和 HTTP/2
Posted
技术标签:
【中文标题】使用 Express.js 的多个 SSL 证书和 HTTP/2【英文标题】:Multiple SSL Certificates and HTTP/2 with Express.js 【发布时间】:2017-07-20 06:05:13 【问题描述】:场景:
我有一个 express.js 服务器,它根据 req.headers.host
所说的用户来自哪里提供相同静态登录页面的变体 - 有点像 A/B 测试。
GET tulip.flower.com
服务于pages/flower.com/tulip.html
GET rose.flower.com
服务于pages/flower.com/rose.html
同时,这个IP还负责:
GET potato.vegetable.com
服务pages/vegetable.com/potato.html
提供这些页面FAST很重要,因此它们经过预编译和优化in all sorts of ways。
服务器现在需要:
-
为
*.vegetables.com
、*.fruits.com
、*.rocks.net
提供单独的证书
可选择不为*.flowers.com
提供证书
提供 HTTP2
问题在于 HTTP2 需要一个证书,而现在有多个证书在起作用。
it's possible 似乎在一个 Node.js(并且可能通过扩展名 Express.js)服务器上使用多个证书,但是否可以将其与 spdy 之类的模块结合使用,如果可以,如何?
与其破解节点,不如将整理http2和SSL的任务典当给nginx会不会更聪明?像 Imperva 或 Akamai 这样的缓存网络应该处理这个问题吗?
【问题讨论】:
【参考方案1】:你也可以使用 tls.createSecureContext,Nginx 不是必需的。
这里是我的例子:
const https = require("https");
const tls = require("tls");
const certs =
"localhost":
key: "./certs/localhost.key",
cert: "./certs/localhost.crt",
,
"example.com":
key: "./certs/example.key",
cert: "./certs/example.cert",
ca: "./certs/example.ca",
,
function getSecureContexts(certs)
if (!certs || Object.keys(certs).length === 0)
throw new Error("Any certificate wasn't found.");
const certsToReturn = ;
for (const serverName of Object.keys(certs))
const appCert = certs[serverName];
certsToReturn[serverName] = tls.createSecureContext(
key: fs.readFileSync(appCert.key),
cert: fs.readFileSync(appCert.cert),
// If the 'ca' option is not given, then node.js will use the default
ca: appCert.ca ? sslCADecode(
fs.readFileSync(appCert.ca, "utf8"),
) : null,
);
return certsToReturn;
// if CA contains more certificates it will be parsed to array
function sslCADecode(source)
if (!source || typeof (source) !== "string")
return [];
return source.split(/-----END CERTIFICATE-----[\s\n]+-----BEGIN CERTIFICATE-----/)
.map((value, index: number, array) =>
if (index)
value = "-----BEGIN CERTIFICATE-----" + value;
if (index !== array.length - 1)
value = value + "-----END CERTIFICATE-----";
value = value.replace(/^\n+/, "").replace(/\n+$/, "");
return value;
);
const secureContexts = getSecureContexts(certs)
const options =
// A function that will be called if the client supports SNI TLS extension.
SNICallback: (servername, cb) =>
const ctx = secureContexts[servername];
if (!ctx)
log.debug(`Not found SSL certificate for host: $servername`);
else
log.debug(`SSL certificate has been found and assigned to $servername`);
if (cb)
cb(null, ctx);
else
return ctx;
,
;
var https = require('https');
var httpsServer = https.createServer(options, (req, res) => console.log(res, req));
httpsServer.listen(443, function ()
console.log("Listening https on port: 443")
);
如果你想测试它:
编辑 /etc/hosts 并添加记录 127.0.0.1 example.com
用网址https://example.com:443
打开浏览器
【讨论】:
我知道 Nginx 是执行此操作的首选方式,但我喜欢这个答案,因为它实际上回答了所提出的问题。此外,这个答案只是为我节省了今天需要完成的修补程序,并且我没有时间重新配置我的整个站点。谢谢!【参考方案2】:Nginx 可以很好地处理 SSL 终止,这将减轻您的应用程序服务器的 ssl 处理能力。
如果您的 nginx 和应用程序服务器之间有一个安全的专用网络,我建议您通过 nginx 反向代理卸载 ssl。在这种实践中,nginx 将监听 ssl,(证书将在 nginx 服务器上管理)然后它将代理请求反向到非 ssl 上的应用程序服务器(因此应用程序服务器不需要证书,没有 ssl 配置和 ssl 进程负担)。
如果您的 nginx 和应用程序服务器之间没有安全的专用网络,您仍然可以通过将上游配置为 ssl 将 nginx 用作反向代理,但您将失去卸载的好处。
CDN 也可以做到这一点。它们基本上是反向代理 + 缓存,所以我看不出有问题。
Good read.
【讨论】:
所以你是说我应该从 node.js 服务器中完全删除 http2 并让其他人(nginx、cdn)处理这些事情? 这是可能的,您也可以在节点服务器上保留 http2,但在此处删除 ssl,并在 nginx 服务器上终止 ssl。更新了答案并阅读。【参考方案3】:让我们用Greenlock Express v3 加密
我是 Greenlock Express 的作者,它是用于 Node.js、Express 等的 Let's Encrypt,而这个用例正是我所做的。
基本设置如下所示:
require("greenlock-express")
.init(function getConfig()
return
package: require("./package.json")
manager: 'greenlock-manager-fs',
cluster: false,
configFile: '~/.config/greenlock/manager.json'
;
)
.serve(httpsWorker);
function httpsWorker(server)
// Works with any Node app (Express, etc)
var app = require("./my-express-app.js");
// See, all normal stuff here
app.get("/hello", function(req, res)
res.end("Hello, Encrypted World!");
);
// Serves on 80 and 443
// Get's SSL certificates magically!
server.serveApp(app);
它也适用于节点集群,因此您可以利用多个核心。
它使用SNICallback
动态添加证书。
网站管理
默认管理器插件使用文件系统上的文件,但有great documentation 说明如何构建自己的。
刚开始,基于文件的插件使用如下配置文件:
~/.config/greenlock/manager.json
:
"subscriberEmail": "letsencrypt-test@therootcompany.com",
"agreeToTerms": true,
"sites": [
"subject": "example.com",
"altnames": ["example.com", "www.example.com"]
]
非常可扩展
我无法在此处发布所有可能的选项,但它非常小且易于开始,并且很容易根据需要使用高级选项进行扩展。
【讨论】:
看起来不错,但是……缺少文档。更不用说使用自托管 git 上的代码而不是例如使用代码感到不安全。 Github,所以它可以消失:/我找不到任何关于为 v4 创建自定义管理器的文档。你能帮忙吗?以上是关于使用 Express.js 的多个 SSL 证书和 HTTP/2的主要内容,如果未能解决你的问题,请参考以下文章
无法使用 Spring Boot 连接到具有多个 SSL 证书的多个 IBM MQ 通道