【问题标题】:Enabling HTTPS on express.js在 express.js 上启用 HTTPS
【发布时间】:2012-07-29 12:09:40
【问题描述】:

我正在尝试让 HTTPS 在 node 的 express.js 上运行,但我无法弄清楚。

这是我的app.js 代码。

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

var privateKey = fs.readFileSync('sslcert/server.key');
var certificate = fs.readFileSync('sslcert/server.crt');

var credentials = {key: privateKey, cert: certificate};


var app = express.createServer(credentials);

app.get('/', function(req,res) {
    res.send('hello');
});

app.listen(8000);

当我运行它时,它似乎只响应 HTTP 请求。

我写了一个简单的基于香草node.js 的HTTPS 应用程序:

var   fs = require("fs"),
      http = require("https");

var privateKey = fs.readFileSync('sslcert/server.key').toString();
var certificate = fs.readFileSync('sslcert/server.crt').toString();

var credentials = {key: privateKey, cert: certificate};

var server = http.createServer(credentials,function (req, res) {
  res.writeHead(200, {'Content-Type': 'text/plain'});
  res.end('Hello World\n');
});

server.listen(8000);

当我运行这个应用程序时,它确实响应 HTTPS 请求。请注意,我认为 fs 结果上的 toString() 并不重要,因为我使用了两者的组合,但仍然没有 es bueno。


编辑添加:

对于生产系统,您最好使用 Nginx 或 HAProxy 将请求代理到您的 nodejs 应用程序。您可以设置 nginx 来处理 ssl 请求,然后将 http 与您的节点 app.js 对话。

编辑添加(2015 年 4 月 6 日)

对于使用 AWS 的系统,您最好使用 EC2 弹性负载均衡器来处理 SSL 终止,并允许定期 HTTP 流量到您的 EC2 Web 服务器。为了进一步提高安全性,请设置您的安全组,以便只允许 ELB 将 HTTP 流量发送到 EC2 实例,这将防止外部未加密的 HTTP 流量到达您的计算机。


【问题讨论】:

  • 在这里简洁地回答:stackoverflow.com/a/23894573/1882064
  • 关于AWS的最后一条评论:是不是不需要用https模块创建服务器?我的证书通过 Jenkins 上传到 AWS 并由 ARN 处理;我没有要使用的文件路径(在 https 选项中)
  • @sqldoug 我不确定我是否理解这个问题。 AWS ELB 可以配置为接受 HTTPS 连接并充当 SSL 终止点。也就是说,它们通过常规 HTTP 与您的应用服务器通信。通常没有理由让 nodejs 处理 SSL,因为它只是额外的处理开销,可以在 ELB 级别或 HTTP 代理级别处理堆栈。
  • 谢谢艾伦;是的,我已经意识到,当 AWS ELB 可以这样配置时,Node 不需要处理 SSL。

标签: node.js https express


【解决方案1】:

这个答案与 Setthase 非常相似,但它适用于 LetsEncrypt (Ubuntu)

// Dependencies
const fs = require('fs');
const http = require('http');
const https = require('https');
const express = require('express');

const app = express();

// Certificate
const privateKey = fs.readFileSync('/etc/letsencrypt/live/yourdomain.com/privkey.pem', 'utf8');
const certificate = fs.readFileSync('/etc/letsencrypt/live/yourdomain.com/cert.pem', 'utf8');
const ca = fs.readFileSync('/etc/letsencrypt/live/yourdomain.com/chain.pem', 'utf8');

const credentials = {
    key: privateKey,
    cert: certificate,
    ca: ca
};

app.use((req, res) => {
    res.send('Hello there !');
});

// Starting both http & https servers
const httpServer = http.createServer(app);
const httpsServer = https.createServer(credentials, app);

httpServer.listen(80, () => {
    console.log('HTTP Server running on port 80');
});

httpsServer.listen(443, () => {
    console.log('HTTPS Server running on port 443');
});

您可能会遇到:EACCES:权限被拒绝,打开 '/etc/letsencrypt/live/yourdeomain.com/privkey.pem'

答案在这里:Let's encrypt SSL couldn't start by "Error: EACCES: permission denied, open '/etc/letsencrypt/live/domain.net/privkey.pem'"

在 ubuntu ssh 终端中对我有用的是 获取用户whoami

// Create group with root and nodeuser as members
$ sudo addgroup nodecert
$ sudo adduser ubuntu nodecert
$ sudo adduser root nodecert

// Make the relevant letsencrypt folders owned by said group.
$ sudo chgrp -R nodecert /etc/letsencrypt/live
$ sudo chgrp -R nodecert /etc/letsencrypt/archive

// Allow group to open relevant folders
$ sudo chmod -R 750 /etc/letsencrypt/live
$ sudo chmod -R 750 /etc/letsencrypt/archive

sudo reboot

【讨论】:

  • 它按预期工作,我们还需要在 Linux 上打开端口。谢谢!
【解决方案2】:

不要忘记凭据中的 PEM 密码!

当您使用 OpenSSL 生成凭据时(不要忘记 -sha256 标志):

OpenSSL> req -x509 -sha256 -newkey rsa:4096 -keyout key.pem -out cert.pem -days 365
Generating a RSA private key

writing new private key to 'key.pem'
Enter PEM pass phrase:
Verifying - Enter PEM pass phrase:

你的 JS/TS 代码:

const credentials = {key: privateKey, cert: certificate, passphrase: 'YOUR passphrase'};

Reference

【讨论】:

    【解决方案3】:

    首先,您需要创建 selfsigned.keyselfsigned.crt 文件。 转至Create a Self-Signed SSL Certificate 或执行以下步骤。

    转到终端并运行以下命令。

    sudo openssl req -x509 -nodes -days 365 -newkey rsa:2048 -keyout ./selfsigned.key -out selfsigned.crt

    • 然后输入以下信息
    • 国家名称(2 个字母代码)[AU]:美国
    • 州或省名称(全名)[Some-State]:NY
    • 地区名称(例如,城市)[]:NY
    • 组织名称(例如,公司)[Internet Widgits Pty Ltd]:xyz(您的组织)
    • 组织单位名称(例如,部分)[]:xyz(您的单位名称)
    • 通用名称(例如服务器 FQDN 或您的姓名)[]:www.xyz.com(您的网址)
    • 电子邮件地址 []:您的电子邮件

    创建后在您的代码中添加密钥和证书文件,并将选项传递给服务器。

    const express = require('express');
    const https = require('https');
    const fs = require('fs');
    const port = 3000;
    
    var key = fs.readFileSync(__dirname + '/../certs/selfsigned.key');
    var cert = fs.readFileSync(__dirname + '/../certs/selfsigned.crt');
    var options = {
      key: key,
      cert: cert
    };
    
    app = express()
    app.get('/', (req, res) => {
       res.send('Now using https..');
    });
    
    var server = https.createServer(options, app);
    
    server.listen(port, () => {
      console.log("server starting on port : " + port)
    });
    
    • 最后使用 https 运行您的应用程序。

    更多信息https://github.com/sagardere/set-up-SSL-in-nodejs

    【讨论】:

    • 除非必要,否则不建议使用 sudo。我只是在没有使用 sudo 的情况下完成了这个过程,但是我在机器上以管理员身份登录。
    • 以上代码适用于我的情况,我遇到了“EACCES:权限被拒绝,打开'/etc/letsencrypt/live/domain.net/privkey.pem'”错误。我运行@987654326 @ 成功了。ubuntu 是用户名,你可以用用户名替换它。
    • 如果我想使用变量而不是像'/../certs/selfsigned.key' 这样的硬编码路径,我想知道如何让 readFileSync 工作。查看问题:stackoverflow.com/questions/56744208/…
    • 我的问题是 nodejs 一直告诉我 createServer 不起作用。我的 nodejs 版本是 11.15.0。有什么想法吗?
    • NET::ERR_CERT_AUTHORITY_INVALID
    【解决方案4】:

    这是我的 工作代码,用于 express 4.0

    express 4.0 与 3.0 和其他版本非常不同。

    4.0 你有 /bin/www 文件,你要在这里添加 https。

    “npm start”是启动 express 4.0 服务器的标准方式。

    readFileSync() 函数应该使用 __dirname 获取当前目录

    而 require() 使用 ./ 引用当前目录。

    首先将 private.key 和 public.cert 文件放在 /bin 文件夹下, 它与 WWW 文件位于同一文件夹

    【讨论】:

      【解决方案5】:

      使用 greenlock-express:免费 SSL、自动 HTTPS

      Greenlock 处理证书颁发和更新(通过 Let's Encrypt)和 http => https 重定向,开箱即用。

      express-app.js:

      var express = require('express');
      var app = express();
      
      app.use('/', function (req, res) {
        res.send({ msg: "Hello, Encrypted World!" })
      });
      
      // DO NOT DO app.listen()
      // Instead export your app:
      module.exports = app;
      

      server.js:

      require('greenlock-express').create({
        // Let's Encrypt v2 is ACME draft 11
        version: 'draft-11'
      , server: 'https://acme-v02.api.letsencrypt.org/directory'
      
        // You MUST change these to valid email and domains
      , email: 'john.doe@example.com'
      , approveDomains: [ 'example.com', 'www.example.com' ]
      , agreeTos: true
      , configDir: "/path/to/project/acme/"
      
      , app: require('./express-app.j')
      
      , communityMember: true // Get notified of important updates
      , telemetry: true       // Contribute telemetry data to the project
      }).listen(80, 443);
      

      截图

      观看快速入门演示:https://youtu.be/e8vaR4CEZ5s

      对于本地主机

      提前回答这个问题,因为这是一个常见的后续问题:

      您不能在本地主机上拥有 SSL 证书。但是,您可以使用 Telebit 之类的东西,这样您就可以将本地应用程序作为真实应用程序运行。

      您还可以通过 DNS-01 挑战将私有域与 Greenlock 一起使用,自述文件中提到了这一点以及支持它的各种插件。

      非标准端口(即没有 80 / 443)

      阅读上面关于 localhost 的说明 - 您也不能在 Let's Encrypt 中使用非标准端口。

      但是,您可以通过端口转发、sni-route 将内部非标准端口公开为外部标准端口,或者使用 Telebit 之类的东西为您执行 SNI 路由和端口转发/中继。

      您还可以使用 DNS-01 挑战,在这种情况下您根本不需要公开端口,并且您还可以通过这种方式保护专用网络上的域。

      【讨论】:

      • "您不能在本地主机上拥有 SSL 证书。" -- 我在本地主机上的 React 应用程序上使用 SSL。来到这里寻找如何让它在 Express 中工作。 React 是我的前端,Express 是我的后端。需要它为 Stripe 工作,因为我在 Stripe 的帖子必须使用 SSL。应该很明显,但是在 localhost 我正在测试,并且在服务器上它将是生产的。
      • 更正:“您不能在本地主机上拥有 有效 SSL 证书”。
      【解决方案6】:

      这就是它为我工作的方式。使用的重定向也会重定向所有正常的http。

      const express = require('express');
      const bodyParser = require('body-parser');
      const path = require('path');
      const http = require('http');
      const app = express();
      var request = require('request');
      //For https
      const https = require('https');
      var fs = require('fs');
      var options = {
        key: fs.readFileSync('certificates/private.key'),
        cert: fs.readFileSync('certificates/certificate.crt'),
        ca: fs.readFileSync('certificates/ca_bundle.crt')
      };
      
      // API file for interacting with MongoDB
      const api = require('./server/routes/api');
      
      // Parsers
      app.use(bodyParser.json());
      app.use(bodyParser.urlencoded({ extended: false }));
      
      // Angular DIST output folder
      app.use(express.static(path.join(__dirname, 'dist')));
      
      // API location
      app.use('/api', api);
      
      // Send all other requests to the Angular app
      app.get('*', (req, res) => {
        res.sendFile(path.join(__dirname, 'dist/index.html'));
      });
      app.use(function(req,resp,next){
        if (req.headers['x-forwarded-proto'] == 'http') {
            return resp.redirect(301, 'https://' + req.headers.host + '/');
        } else {
            return next();
        }
      });
      
      
      http.createServer(app).listen(80)
      https.createServer(options, app).listen(443);
      

      【讨论】:

      • 我的问题是 nodejs 一直告诉我 createServer 不起作用。我的 nodejs 版本是 11.15.0。有什么想法吗?
      • 实际上我发现了我的问题。我有这条线const https = require('https').Server(app); 并尝试了这条https.createServer(options,app); 那是我不断收到createServer is not function 错误的时候。然后,仔细研究像你这样的例子。然后我明白了为什么我有问题。我只需要这个const https = require('https'); 谢谢你的回复。
      【解决方案7】:

      包括积分:

      1. SSL 设置
        1. 在 config/local.js 中
        2. 在 config/env/production.js 中

      HTTP 和 WS 处理

      1. 开发中的应用程序必须在 HTTP 上运行,以便我们可以轻松调试我们的 应用程序。
      2. 出于安全考虑,该应用必须在生产环境中使用 HTTPS 运行。
      3. 应用生产 HTTP 请求应始终重定向到 https。

      SSL 配置

      在 Sailsjs 中,有两种配置所有东西的方法,第一种是在 config 文件夹中进行配置,每个文件都有其单独的文件(例如有关设置的数据库连接位于 connections.js 中)。其次是配置环境基础文件结构,每个环境文件都存在于config/env文件夹中,每个文件都包含特定环境的设置。

      Sails先看config/env文件夹,然后期待config/*.js

      现在让我们在 config/local.js 中设置 ssl。

      var local = {
         port: process.env.PORT || 1337,
         environment: process.env.NODE_ENV || 'development'
      };
      
      if (process.env.NODE_ENV == 'production') {
          local.ssl = {
              secureProtocol: 'SSLv23_method',
              secureOptions: require('constants').SSL_OP_NO_SSLv3,
              ca: require('fs').readFileSync(__dirname + '/path/to/ca.crt','ascii'),
              key: require('fs').readFileSync(__dirname + '/path/to/jsbot.key','ascii'),
              cert: require('fs').readFileSync(__dirname + '/path/to/jsbot.crt','ascii')
          };
          local.port = 443; // This port should be different than your default port
      }
      
      module.exports = local;
      

      您也可以在 config/env/production.js 中添加它。 (这个 sn-p 还展示了如何处理多个 CARoot 证书)

      或者在 production.js

      module.exports = {
          port: 443,
          ssl: {
              secureProtocol: 'SSLv23_method',
              secureOptions: require('constants').SSL_OP_NO_SSLv3,
              ca: [
                  require('fs').readFileSync(__dirname + '/path/to/AddTrustExternalCARoot.crt', 'ascii'),
                  require('fs').readFileSync(__dirname + '/path/to/COMODORSAAddTrustCA.crt', 'ascii'),
                  require('fs').readFileSync(__dirname + '/path/to/COMODORSADomainValidationSecureServerCA.crt', 'ascii')
              ],
              key: require('fs').readFileSync(__dirname + '/path/to/jsbot.key', 'ascii'),
              cert: require('fs').readFileSync(__dirname + '/path/to/jsbot.crt', 'ascii')
          }
      };
      

      http/https & ws/wss 重定向

      这里 ws 是 Web Socket,wss 代表 Secure Web Socket,因为我们设置了 ssl,然后现在 http 和 ws 两个请求都变得安全并分别转换为 https 和 wss。

      我们的应用程序有许多来源会像任何博客文章、社交媒体文章一样接收请求,但我们的服务器仅在 https 上运行,因此当任何来自 http 的请求时,它会在客户端浏览器中显示“无法访问此站点”错误.我们失去了我们的网站流量。所以我们必须将http请求重定向到https,同样的规则允许websocket,否则socket会失败。

      所以我们需要在端口 80 (http) 上运行相同的服务器,并将所有请求转移到端口 443(https)。 Sails 在提升服务器之前首先编译 config/bootstrap.js 文件。在这里,我们可以在端口 80 上启动我们的 express 服务器。

      在 config/bootstrap.js 中(创建 http 服务器并将所有请求重定向到 https)

      module.exports.bootstrap = function(cb) {
          var express = require("express"),
              app = express();
      
          app.get('*', function(req, res) {  
              if (req.isSocket) 
                  return res.redirect('wss://' + req.headers.host + req.url)  
      
              return res.redirect('https://' + req.headers.host + req.url)  
          }).listen(80);
          cb();
      };
      

      现在你可以访问http://www.yourdomain.com,它会重定向到https://www.yourdomain.com

      【讨论】:

        【解决方案8】:

        在 express.js(从版本 3 开始)中,您应该使用该语法:

        var fs = require('fs');
        var http = require('http');
        var https = require('https');
        var privateKey  = fs.readFileSync('sslcert/server.key', 'utf8');
        var certificate = fs.readFileSync('sslcert/server.crt', 'utf8');
        
        var credentials = {key: privateKey, cert: certificate};
        var express = require('express');
        var app = express();
        
        // your express configuration here
        
        var httpServer = http.createServer(app);
        var httpsServer = https.createServer(credentials, app);
        
        httpServer.listen(8080);
        httpsServer.listen(8443);
        

        这样你就可以为本地 http/https 服务器提供快速中间件

        如果您希望您的应用在低于 1024 的端口上运行,则需要使用 sudo 命令(不推荐)或使用反向代理(例如 nginx、haproxy)。

        【讨论】:

        • 全部写在这里:github.com/visionmedia/express/wiki/Migrating-from-2.x-to-3.x段落应用函数
        • 请注意,虽然 443 是 HTTPS 的默认端口,但在开发过程中您可能希望使用 8443 之类的端口,因为大多数系统不允许在低编号端口上使用非 root 侦听器。
        • 伙计,它就像魔术一样工作 :) 它也接受 .pem 文件,无论如何它应该接受
        • express 4 它不起作用,它适用于localhost:80 但不适用于https://localhost:443
        • 如果您打算使用 nginx 进行反向代理,它可以为您处理 ssl 证书而不是节点
        【解决方案9】:

        我在让 SSL 在端口 443 以外的端口上工作时遇到了类似的问题。在我的情况下,我有一个捆绑证书以及一个证书和一个密钥。捆绑证书是一个包含多个证书的文件,节点要求您将这些证书分解为数组的单独元素。

            var express = require('express');
            var https = require('https');
            var fs = require('fs');
        
            var options = {
              ca: [fs.readFileSync(PATH_TO_BUNDLE_CERT_1), fs.readFileSync(PATH_TO_BUNDLE_CERT_2)],
              cert: fs.readFileSync(PATH_TO_CERT),
              key: fs.readFileSync(PATH_TO_KEY)
            };
        
            app = express()
        
            app.get('/', function(req,res) {
                res.send('hello');
            });
        
            var server = https.createServer(options, app);
        
            server.listen(8001, function(){
                console.log("server running at https://IP_ADDRESS:8001/")
            });
        

        在 app.js 中,您需要指定 https 并相应地创建服务器。此外,请确保您尝试使用的端口实际上允许入站流量。

        【讨论】:

        • 我有一个密钥和一个捆绑的证书,我不确定什么证书:fs.readFileSync(PATH_TO_CERT),以及如何“破坏”捆绑的证书,里面有 20 多个密钥如果你问我,请证明:)
        • @MuhammadUmar 您不必破坏捆绑包,如果没有,您甚至不必指定它,如果适用,您将拥有捆绑包证书,以及证书(公钥)和密钥(私钥)跨度>
        • @eomoto 谢谢芽!这是最好的,你完全掌握了我需要的例子
        • 如果我想使用像PATH_TO_BUNDLE_CERT_1 这样的变量,我想知道如何让 readFileSync 工作。查看问题:stackoverflow.com/questions/56744208/…
        • 我的问题是 nodejs 一直告诉我 createServer 不起作用。我的 nodejs 版本是 11.15.0。有什么想法吗?
        猜你喜欢
        • 2017-02-14
        • 2020-12-28
        • 1970-01-01
        • 2017-11-06
        • 2018-10-28
        • 2017-03-12
        • 2020-12-15
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多