场景:
我有一个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强制要求证书,现在有多个证书可供使用。
似乎it's possible在一个Node.js(可能是扩展名为Express.js)服务器上使用多个证书,但是可以将它与spdy之类的模块结合使用,如果那怎么样?
而不是黑客入侵节点,将http2和SSL整理到nginx的任务更聪明吗?像Imperva或Akamai这样的缓存网络应该处理这个吗?
答案 0 :(得分:1)
Nginx可以很好地处理SSL终止,这将从您的应用服务器卸载ssl处理能力。
如果你的nginx和应用服务器之间有一个安全的专用网络,我建议你通过nginx反向代理卸载ssl。在这种实践中,nginx将侦听ssl,(证书将在nginx服务器上管理)然后它将在非ssl上反向代理请求到应用程序服务器(因此应用程序服务器不需要在它们上面有证书,没有ssl配置和没有ssl进程负担)。
如果您的nginx和应用程序服务器之间没有安全的专用网络,您仍然可以通过将上游配置为ssl来使用nginx作为反向代理,但是您将失去卸载权益。
CDN也可以这样做。它们基本上是反向代理+缓存,所以我没有看到问题。
答案 1 :(得分:0)
您还可以使用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
答案 2 :(得分:0)
我是Greenlock Express的作者,Greenlock Express是让我们为Node.js,Express等进行加密的工具,而这种用例正是我所为的。
基本设置如下:
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"]
}
]
}
我无法在此处发布所有可能的选项,但是起步非常小且简单,并且可以根据需要使用高级选项轻松扩展。