如何在Node.js中创建一个HTTPS服务器?

409

有了SSL密钥和证书,如何创建HTTPS服务?


2
我使用了restify.js而不是express.js,但思路是相同的。以下是我如何设置一个接受HTTP和HTTPS的node.js服务器的方法:http://qugstart.com/blog/node-js/node-js-restify-server-with-both-http-and-https/ - awaage
2
请使用最新版本的Node,查看此处链接:https://dev59.com/a2025IYBdhLWcg3wclq-#21809393。 - Philipp Kyeck
1
这个问题发生了什么?答案表明它最初是关于express.js的。 - doug65536
创建有效的自签名 SSL 证书并启动 HTTPS 服务器非常容易,只需几个步骤 - Lloyd
4
如果有人需要完整的Node.js HTTPS教程,可以在这里找到:http://programmerblog.net/nodejs-https-server/。虽然有点晚,但我希望你能理解。 - Maz I
显示剩余3条评论
10个回答

531

Express API文档非常清楚地解释了这一点。

此外,这个答案提供了创建自签名证书的步骤。

我添加了一些注释和Node.js HTTPS文档中的代码片段:

var express = require('express');
var https = require('https');
var http = require('http');
var fs = require('fs');

// This line is from the Node.js HTTPS documentation.
var options = {
  key: fs.readFileSync('test/fixtures/keys/agent2-key.pem'),
  cert: fs.readFileSync('test/fixtures/keys/agent2-cert.cert')
};

// Create a service (the app object is just a callback).
var app = express();

// Create an HTTP service.
http.createServer(app).listen(80);
// Create an HTTPS service identical to the HTTP service.
https.createServer(options, app).listen(443);

53
很好,我本来也打算发这个帖子的。谢谢。此外,我发现这篇文章对于生成自签名证书非常有帮助。 - clayzermk1
1
确保在 https.createServer 中首先放置 options,以避免出现晦涩的错误。 - wberry
1
我正在设置一个几乎相同的https服务器端口8888,但不确定如何更改路由。当我运行curl curl --insecure https://localhost:8888时,出现以下错误:curl: (35) Unknown SSL protocol error in connection to localhost:8888。这个错误是从哪里来的,如何解决它?当我在浏览器中输入localhost:8888时,它会挂起,https:/localhost:8888会出现SSL错误。 - reza
2
@Costa,你可以使用express-force-ssl或手写中间件将用户从http重定向到https - 这很简单,可以参考这篇文章:http重定向到https - floatdrop
1
@NathanMcKaskle 您可以禁用密码:请查看此指南,但如果您使用的是macOS,请确保生成的密钥长度至少为2048:openssl genrsa -out key.pem 2048 - sakisk
显示剩余8条评论

171

从 Node 0.3.4 版本开始一直到当前的 LTS 版本 (在此编辑时为 v16),https://nodejs.org/api/https.html#httpscreateserveroptions-requestlistener 提供所有你需要的示例代码:

const https = require(`https`);
const fs = require(`fs`);

const options = {
  key: fs.readFileSync(`test/fixtures/keys/agent2-key.pem`),
  cert: fs.readFileSync(`test/fixtures/keys/agent2-cert.pem`)
};

https.createServer(options, (req, res) => {
  res.writeHead(200);
  res.end(`hello world\n`);
}).listen(8000);

请注意,如果想要使用Let's Encrypt的证书并使用Certbot工具,私钥应该被称为privkey.pem,证书应该被称为fullchain.pem

const certDir = `/etc/letsencrypt/live`;
const domain = `YourDomainName`;
const options = {
  key: fs.readFileSync(`${certDir}/${domain}/privkey.pem`),
  cert: fs.readFileSync(`${certDir}/${domain}/fullchain.pem`)
};

3
setSecure 已被弃用。请查看替代方案:https://dev59.com/vW435IYBdhLWcg3w6EqF - Larry Battle
7
请见@Jacob Marble所给的官方回答。 - clayzermk1
22
由于Node.js 0.4重新实现了HTTPS,因此此示例不再适用。请查看nodejs.org上的相应文档。https://dev59.com/vW435IYBdhLWcg3w6EqF?lq=1 - scottyab
12
这个答案已经过时了,不再适用。请查看下面pkyeck的答案,或者前往http://nodejs.org/api/https.html查看。 - Jay Sheth
2
链接已经失效。 - TlonXP
显示剩余3条评论

91

在Google搜索“node https”时发现了这个问题,但被采纳的答案中的示例非常古老 - 取自当前(v0.10)版本的Node.js文档,它应该像这样:

var https = require('https');
var fs = require('fs');

var options = {
  key: fs.readFileSync('test/fixtures/keys/agent2-key.pem'),
  cert: fs.readFileSync('test/fixtures/keys/agent2-cert.pem')
};

https.createServer(options, function (req, res) {
  res.writeHead(200);
  res.end("hello world\n");
}).listen(8000);

运行得非常顺利。这些信息非常有用,因为我在一个PHP应用程序上运行了一个node.js工具(PDFJS),最近被迫使用https运行。iframe无法在另一个非https端口上加载我的node.js应用程序,所以它非常不高兴。 - lewsid
2
这看起来不错,但我该如何生成你所需的文件(*.pem)呢?我尝试了遵循此页面,但在浏览器中打开localhost:8000时,没有接收到任何数据(只是加载...)。 - Ionică Bizău
8
要生成密钥,请安装openssl,然后在命令提示符中键入openssl req -x509 -newkey rsa:2048 -keyout key.pem -out cert.pem -days 3001 - mido
2
@IonicăBizău 你需要直接访问 https://localhost:8080。HTTP 不是 HTTPS。 - Florian Wendelborn
能否创建带有文件夹的https服务器?这样你就可以将文件放进去,并像https://localhost:81/main.js这样访问该文件。 - FrenkyB
@FrenkyB,有一个 https://github.com/cloudhead/node-static 可以帮助你解决这个问题。 - Philipp Kyeck

49

上面的回答都不错,但使用 Express 和 node.js 也可以很好地实现。

由于 Express 会为你创建应用程序,因此我在这里跳过这一步。

var express = require('express')
  , fs = require('fs')
  , routes = require('./routes');

var privateKey = fs.readFileSync('cert/key.pem').toString();
var certificate = fs.readFileSync('cert/certificate.pem').toString();  

// To enable HTTPS
var app = module.exports = express.createServer({key: privateKey, cert: certificate});

12
由于“应用程序不再从http.Server继承”,因此这似乎已被弃用。 - Merlyn Morgan-Graham
2
为什么要设置 module.exports?这并不必要。 - Matej
1
@matejkramny,可能是因为这样可以方便测试。 - Justin

23
在Node.js中建立HTTPS服务器的最基本设置如下所示:
var https = require('https');
var fs = require('fs');

var httpsOptions = {
    key: fs.readFileSync('path/to/server-key.pem'),
    cert: fs.readFileSync('path/to/server-crt.pem')
};

var app = function (req, res) {
  res.writeHead(200);
  res.end("hello world\n");
}

https.createServer(httpsOptions, app).listen(4433);

如果你想支持HTTP请求,只需要进行一小处修改:

var http = require('http');
var https = require('https');
var fs = require('fs');

var httpsOptions = {
    key: fs.readFileSync('path/to/server-key.pem'),
    cert: fs.readFileSync('path/to/server-crt.pem')
};

var app = function (req, res) {
  res.writeHead(200);
  res.end("hello world\n");
}

http.createServer(app).listen(8888);
https.createServer(httpsOptions, app).listen(4433);

2
所有这些答案都是旧的和过时的。我希望StackOverflow能够清理掉非常非常老的问题和答案。createServer已经被弃用了!这个函数不再存在。 - ThN
你在说什么?你是说 createServer 已经不存在了吗?它仍然在 Node.js v16.5.0 的文档中有记录,而且在 https://nodejs.org/api/http.html 和 https://nodejs.org/api/https.html 中都没有被标记为弃用。你真的尝试运行过这段代码吗?如果是的话,你遇到了哪些错误? - John Slegers
1
实际上我找到了我的错误。有一行需要更改 var https = require('https').Server(app);var https = require('https'); 现在,一切都正常了...谢谢。 - ThN

18

更新

使用Greenlock.js通过Let's Encrypt进行

原始帖子

我注意到这些答案都没有显示如何添加中间根证书颁发机构到链中,以下是一些零配置示例,可供尝试查看:

片段:

var options = {
  // this is the private key only
  key: fs.readFileSync(path.join('certs', 'my-server.key.pem'))

// this must be the fullchain (cert + intermediates)
, cert: fs.readFileSync(path.join('certs', 'my-server.crt.pem'))

// this stuff is generally only for peer certificates
//, ca: [ fs.readFileSync(path.join('certs', 'my-root-ca.crt.pem'))]
//, requestCert: false
};

var server = https.createServer(options);
var app = require('./my-express-or-connect-app').create(server);
server.on('request', app);
server.listen(443, function () {
  console.log("Listening on " + server.address().address + ":" + server.address().port);
});

var insecureServer = http.createServer();
server.listen(80, function () {
  console.log("Listening on " + server.address().address + ":" + server.address().port);
});

这是其中一件事情,通常更容易的方法不是通过连接或表达式直接完成,而是让本机https模块处理它,然后使用它来为您提供连接/表达式应用程序。此外,如果您在创建服务器时使用server.on('request', app)而不是传递应用程序,则可以将server实例传递给某些初始化函数,该函数创建连接/表达式应用程序(例如,如果您想在同一服务器上进行基于ssl的websockets)。

这是一个很好的说明,但是更新部分提供的链接已经失效了(产生了500错误)。 - Chucky
1
所有这些答案都是古老而过时的。我希望StackOverflow能够清理掉非常非常古老的问题和答案。 - ThN
@ThN 你遇到了什么问题?有没有更新、更好的解决方案? - coolaj86
1
@coolaj86 经过长时间的尝试和波折(哈哈),我终于找到了问题所在。现在它可以工作了。我有一行代码 var https = require("https").server(app); 当我使用 https.createServer(...) 创建服务器时,我收到了错误消息 createServer 未找到。将该行更改为 var https = require("https"); 后,一切都顺利了。谢谢... - ThN

10
为了使您的应用程序能够同时监听端口80443上的httphttps,请执行以下操作:
创建一个Express应用程序:
var express = require('express');
var app = express();
< p>由< code>express()返回的应用程序是JavaScript函数。它可以作为回调传递给Node的HTTP服务器以处理请求。这使得使用相同的代码库轻松提供应用程序的HTTP和HTTPS版本。

您可以按如下方式执行:

var express = require('express');
var https = require('https');
var http = require('http');
var fs = require('fs');
var app = express();

var options = {
  key: fs.readFileSync('/path/to/key.pem'),
  cert: fs.readFileSync('/path/to/cert.pem')
};

http.createServer(app).listen(80);
https.createServer(options, app).listen(443);

完整详情请参见文档


1
你可以使用Fastify框架来归档此内容:
const { readFileSync } = require('fs')
const Fastify = require('fastify')

const fastify = Fastify({
  https: {
    key: readFileSync('./test/asset/server.key'),
    cert: readFileSync('./test/asset/server.cert')
  },
  logger: { level: 'debug' }
})

fastify.listen(8080)

(如果您需要编写测试),请运行openssl req -nodes -new -x509 -keyout server.key -out server.cert创建文件。


1
非常感谢您提供的 Fastify 示例,朋友。 - Boris Ivanov

0
如果您只需要在本地进行开发,我已经为此创建了一个实用程序 - https://github.com/pie6k/easy-https
import { createHttpsDevServer } from 'easy-https';

async function start() {
  const server = await createHttpsDevServer(
    async (req, res) => {
      res.statusCode = 200;
      res.write('ok');
      res.end();
    },
    {
      domain: 'my-app.dev',
      port: 3000,
      subdomains: ['test'], // will add support for test.my-app.dev
      openBrowser: true,
    },
  );
}

start();

它:

  • 将自动添加正确的域名条目到 /etc/hosts
  • 仅在第一次运行或更改域名时需要请求管理员密码
  • 将为给定的域名准备 https 证书
  • 将在您的本地计算机上信任这些证书
  • 将在启动时打开浏览器,指向您的本地服务器 https url

-4
  1. 从这里下载openssl设置的rar文件:https://indy.fulgan.com/SSL/openssl-0.9.8r-i386-win32-rev2.zip
  2. 将您的文件夹复制到C驱动器中。
  3. 创建openssl.cnf文件并从此处下载其内容:http://web.mit.edu/crypto/openssl.cnf openssl.cnf可以放在任何地方,但在命令提示符中给出路径时应正确。
  4. 打开命令提示符并设置openssl.cnf路径 C:\set OPENSSL_CONF=d:/openssl.cnf 5.在cmd中运行:C:\openssl-0.9.8r-i386-win32-rev2>openssl.exe
  5. 然后运行OpenSSL> genrsa -des3 -out server.enc.key 1024
  6. 然后它会要求输入密码短语:输入4到11个字符作为证书的密码
  7. 然后运行Openssl>req -new -key server.enc.key -out server.csr
  8. 然后它会要求一些详细信息,如国家代码、州名等,请自由填写。 10 . 然后运行 Openssl > rsa -in server.enc.key -out server.key
  9. 运行此命令 OpenSSL> x509 -req -days 365 -in server.csr -signkey server.key -out server.crt,然后使用Stack Overflow上的先前代码 谢谢

2
这是OT。楼主的问题很清晰。证书已经发放。 - Martin Schneider

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接