【问题标题】:multiple ssl domain in single server单个服务器中的多个 ssl 域
【发布时间】:2019-03-13 20:16:40
【问题描述】:

我使用 digitalocean 来托管 2 个 node.js 应用程序,一个是暂存的,一个是生产的。两者都需要 ssl,我的服务器上有证书。但我在为两者运行 https 时遇到问题。

//socket io config
const server = require('http').createServer(app)
let io = require('socket.io')(server)
 if (process.env.NODE_ENV === 'production' || process.env.NODE_ENV === 'staging') {

      let api_domain, https_port
      if (process.env.NODE_ENV === 'production') {
        api_domain = "api.example.co"
        https_port = 443
      } else if(process.env.NODE_ENV === 'staging') {
        api_domain = "api-staging.example.co"
        https_port = 4431 //this is not working
      }

      const credentials = {
        key: fs.readFileSync(
          '/etc/letsencrypt/live/' + api_domain + '/privkey.pem',
          'utf8'
        ),
        cert: fs.readFileSync(
          '/etc/letsencrypt/live/' + api_domain + '/cert.pem',
          'utf8'
        ),
        ca: fs.readFileSync(
          '/etc/letsencrypt/live/' + api_domain + '/chain.pem',
          'utf8'
        )
      }

      const httpsServer = https.createServer(credentials, app)
//socket io config
  io = require('socket.io')(httpsServer)
  httpsServer.listen(https_port, () => {
    console.log('HTTPS Server started on: ' + port)
  })
    } else {
      //localhost
      server.listen(port, () => {
        console.log('HTTP Server started on: ' + port)
      })
}

我应该如何正确配置端口?

【问题讨论】:

  • 如果 NODE_ENV 是生产,您希望服务器在端口 443 上运行,如果 NODE_ENV 是暂存,您希望服务器在端口 4431 上运行,对吗?不能同时进行吗?
  • @josephting 同时,它是一个 droplet(服务器)上的 2 个应用程序,但问题是如果一个正在运行,另一个会在使用默认为 443 的 SSL 端口时出错。
  • 那么你只需要运行多个服务器实例。 NODE_ENV=production node index.js 在一个窗口中,NODE_ENV=staging node index.js 在另一个窗口中。 https://api.example.cohttps://api-staging.example.co:4431 应该可以同时访问。
  • @josephting 我有多个服务器正在运行,api-staging.example.co:4431 无法访问我的api-staging.example.co 服务器从 3001 端口开始,而生产从 3000 端口开始。

标签: javascript node.js express nginx digital-ocean


【解决方案1】:

我建议不要使用 NodeJS 提供 HTTPS。 使用 nginx 作为反向代理并提供 https 支持是一个更好的主意。

只需在 nginx 中使用 ssl 证书和 proxy_pass 创建两个 vhost 到您的 nodejs 应用程序。

【讨论】:

  • 这不是一回事吗?最后,一个应用程序有 2 个端口,一个用于普通 http,一个用于 https。
  • @Melissa94 结果是一样的……在某种程度上。我认为,通过 NodeJS 处理 HTTPS 效率很低。并且下次可能您更改域或证书时,您需要重新部署代码。
【解决方案2】:

多个实例(不同端口)

在 NodeJS 中,您不能使用单个节点实例运行多个服务器。

您必须使用不同的NODE_ENV 运行多个节点实例才能让两台服务器同时运行。

端口 3000 和 3001 似乎是 NodeJS 使用的默认端口。确保您已正确指定 NODE_ENV

//socket io config
const server = require('http').createServer(app)
let io = require('socket.io')(server)
if (process.env.NODE_ENV === 'production' || process.env.NODE_ENV === 'staging') {

  let api_domain, https_port
  if (process.env.NODE_ENV === 'production') {
    api_domain = "api.example.co"
    https_port = 443
  } else if (process.env.NODE_ENV === 'staging') {
    api_domain = "api-staging.example.co"
    https_port = 4431 //this is not working
  }

  const credentials = {
    key: fs.readFileSync(
      '/etc/letsencrypt/live/' + api_domain + '/privkey.pem',
      'utf8'
    ),
    cert: fs.readFileSync(
      '/etc/letsencrypt/live/' + api_domain + '/cert.pem',
      'utf8'
    ),
    ca: fs.readFileSync(
      '/etc/letsencrypt/live/' + api_domain + '/chain.pem',
      'utf8'
    )
  }

  const httpsServer = https.createServer(credentials, app)
  //socket io config
  io = require('socket.io')(httpsServer)
  httpsServer.listen(https_port, () => {
    console.log('HTTPS Server started on: ' + https_port)
  })
} else {
  //localhost
  server.listen(port, () => {
    console.log('HTTP Server started on: ' + port)
  })
}

然后,您想像这样启动 2 个单独的实例。 假设上面的文件是 index.js

$ NODE_ENV=production node index.js
HTTPS Server started on: 443

$ NODE_ENV=staging node index.js
HTTPS Server started on: 4431

然后您将能够使用以下 URL 访问服务器。

请记住将这些域解析为正确的 IP。

生产 - https://api.example.co

暂存 - https://api-staging.example.co:4431


单实例(同一端口)

如果你想根据主机名来区分环境,你可以使用request.headers.host来确定请求从哪里来和从那里去。

但是,您只能指定每个实例使用 1 个证书。

以下是实现此目的的方法之一。

const path = require('path')
const fs = require('fs')
const https = require('https')

let app = function(req, res) {
  res.writeHead(200, { 'Content-Type': 'text/plain' })
  if (req.headers.host === 'prod.dev.localhost') {
    res.write('Welcome to Production server.')
  } else if (req.headers.host === 'stg.dev.localhost') {
    res.write('Welcome to Staging server.')
  } else {
    res.write('Welcome!')
  }
  res.end()
}

const credentials = {
  key: fs.readFileSync(
    path.join(path.dirname(__filename), 'cert', 'wildcard.dev.localhost.pem'),
    'utf8'
  ),
  cert: fs.readFileSync(
    path.join(path.dirname(__filename), 'cert', 'wildcard.dev.localhost.crt'),
    'utf8'
  )
}

const httpsServer = https.createServer(credentials, app)
let io = require('socket.io')(httpsServer)

httpsServer.listen(443, () => {
  console.log('HTTPS Server started on: ' + 443)
})

【讨论】:

  • 我正在运行 2 个实例。问题是一台服务器只有一个443端口。
  • @Melissa94 这就是为什么您需要在端口 4431 上运行暂存。
  • @Melissa94 可以运行单个实例并提供多个主机名,但不能在单个实例中加载多个证书。我在答案中添加了更多示例代码。如果您想要实现的只是通过 HTTPS 提供内容,那么使用 Nginx 之类的东西来处理会更好。
  • @josepthing,生产和登台在 2 个完全不同的域上,为什么你只有 1 个证书?我使用 if else 来使用正确的证书,我没有启动一个 node.js 服务器,而是启动了 2 个,并且每个服务器都有一个证书。
  • @Melissa94 完全正确。不幸的是,您不能在同一个端口上运行 2 个服务器。这就是为什么我首先建议在顶部使用 Multiple Instances 方法。此处提供了 2 个选项供您参考。我在这里使用通配符证书,它适用于所有 *.dev.localhost 域作为示例。
猜你喜欢
  • 2014-01-25
  • 1970-01-01
  • 2011-09-14
  • 2013-06-11
  • 2013-07-03
  • 2014-11-07
  • 1970-01-01
  • 2020-09-02
  • 2020-12-12
相关资源
最近更新 更多