【问题标题】:How can I run node and apache on the same server to allow the user to access api through https?如何在同一台服务器上运行 node 和 apache 以允许用户通过 https 访问 api?
【发布时间】:2021-10-12 05:41:47
【问题描述】:

我在同一台服务器上运行 Node 和 Apache,其中 node 是后端服务器,由 Axios 请求从前端收集用户数据。

我使用 Apache 通过certbot 请求 SSL 证书,并且成功了。我正在尝试部署节点后端以访问我的endpoint(website.com/endpoint)

我可以看到位于网站文件夹中的测试index.html。当我尝试aws.website.com/endpoint 时,我得到了服务器超时和 404 not found 错误。

我的应用在 Linux 服务器中的位置是var/www/website.com,而不是默认的var/www/html 路径。

我的问题:如何在同一台服务器上运行 node 和 apache 以允许用户通过 https 访问应用程序?

***更新:在我的情况下,您需要节点应用程序在单独的端口上运行 3001,而 Apache 需要在单独的端口上运行,即 80,并通过 mod-proxy 使用反向代理。

这是000-default.conf 文件:

<VirtualHost *:80>
    ProxyPreserveHost On
    ProxyPass / http://18.191.235.31/
    ProxyPassReverse / http://18.191.235.31/
        ServerName aws.website.com
        ServerAdmin example@localhost
        DocumentRoot /var/www/aws.backend-dg.com
</VirtualHost>

这是我用于 Apache 虚拟主机的 config 文件: website/com.conf:

<VirtualHost *:80>
    ServerName aws.website.com
    ...
    DocumentRoot /var/www/aws.website.com
    ...
RewriteEngine on
RewriteCond %{SERVER_NAME} =aws.website.com
RewriteRule ^ https://%{SERVER_NAME}%{REQUEST_URI} [END,NE,R=permanent]
</VirtualHost>

这是我的“website.com.le-ssl.conf”(由 certbot 手动生成)`

<IfModule mod_ssl.c>
<VirtualHost *:443>
    ServerName aws.website.com
    ....
    DocumentRoot /var/www/aws.website.com
    ErrorLog ${APACHE_LOG_DIR}/error.log
    CustomLog ${APACHE_LOG_DIR}/access.log combined

SSLCertificateFile /etc/letsencrypt/live/website/fullchain.pem
SSLCertificateKeyFile /etc/letsencrypt/live/website/privkey.pem
Include /etc/letsencrypt/options-ssl-apache.conf
</VirtualHost>
</IfModule>

这是我的default-ssl.conf

<IfModule mod_ssl.c>
        <VirtualHost _default_:443>
            DocumentRoot /var/www/aws.backend-dg.com
            ....
            ErrorLog ${APACHE_LOG_DIR}/error.log
            CustomLog ${APACHE_LOG_DIR}/access.log combined
            ....
            SSLEngine on
            ....
            SSLCertificateFile      /etc/ssl/certs/ssl-cert-snakeoil.pem
            SSLCertificateKeyFile /etc/ssl/private/ssl-cert-snakeoil.key
            ....
        </VirtualHost>
</IfModule>

App.js 文件

const cors = require("cors");
const mongoose = require("mongoose");
const express = require("express");
const logger = require("morgan");
const app = express();
require("./models/Email");
const routes = require("./routes/routes");

app.use(cors());
app.use((req, res, next) => {
  res.header("Access-Control-Allow-Origin", "*");
  res.header("Access-Control-Allow-Methods", "DELETE, PUT, GET, POST");
  res.header(
    "Access-Control-Allow-Headers",
    "Origin, X-Requested-With, Content-Type, Accept"
  );
  next();
});
app.use(express.json());
app.use(express.urlencoded({ extended: true }));
// Express only serves static assets in production
if (process.env.NODE_ENV === "production") {
  app.use(express.static("client/build"));
}
app.get('*',(req, res) => {
    res.sendFile(path.resolve(__dirname, 'client', 'build', 'index.html'));
});
app.use(express.json());
app.use(logger("dev"));
app.use("/", routes);
app.use("/search", express.static("search"));

const mongoURI =
  "mongodb+srv://somename@cluster................";

const conn = mongoose.createConnection(mongoURI);

mongoose.connect(
  mongoURI,
  { useNewUrlParser: true },
  { useUnifiedTopology: true }
);

conn.once("open", () => {
  console.log("Connection Successful");
});

conn.on("error", console.error.bind(console, "MongoDB connection error:"));

 const server = app.listen(3001, () => {
 console.log(`Express running PORT ${server.address().port}`);
 });


const express = require("express");
const router = express.Router();
const emailController = require('../controllers/EmailController');

router.get('/', emailController.baseRoute);
router.post('back/get-email', emailController.createEmail);

module.exports = router;

【问题讨论】:

  • 你能分享你的 apache ssl conf 吗?它应该对端口 443 进行一些绑定...
  • 因此,您的 express 应用程序应该在某个端口(例如 5005)上运行,并且您的 apache ssl.conf 中应该有一个 proxy_pass 命令...
  • @KemalKaplan 我刚刚用所有配置文件更新了我的问题。关于我的快递服务器,这就是我的问题所在,由于我的域上的 SSL 证书,我不能使用 443 以外的任何其他端口来收听。我尝试了不同的端口,即:444、3000、0 等,每次我尝试使快速服务器保持连接并且握手断开时,错误是该网站不安全:例如 https:aws.website .com:5000 让我出错,网站不安全
  • @KemalKaplan 如何在 SSL conf 中编写 prox cmd?

标签: node.js apache express deployment


【解决方案1】:

答案是保护节点后端服务器,以便用户留在安全的HTTPS 地址上。为此,您可以将 SSL 键分配给节点服务器。然后编辑 app.js 文件以连接到HTTPS,而不是HTTP。以上app.js 仅连接到HTTP。所以这需要修复。最后,编辑您在Apache 虚拟主机中的反向代理,将HTTP 转发到HTTPS

在我的例子中,前端通过 HTTPS SSL 来自 let's encrypt (certbot) 的证书是安全的,即 https://website.com,但后端并不安全,所以当我尝试去 https://websote/endpoint 时是一个错误。 这是因为后端app.js文件在需要连接HTTPS时连接到HTTP服务器。

注意:如果您有一个安全的网站/应用程序,并且您向不安全的HTTP 地址发出 Axios 请求,那么您将收到一个 cors 错误,说明您需要更改 @ 987654344@ 至HTTPS。您可以通过使 node.js 服务器安全来做到这一点。

这是细分:


1a。在节点文件夹中创建一个单独的目录来保存证书。 sudo mkdir directory_name

1b。 *将 SSL 证书从 Apache 服务器复制到 Node 服务器目录。
sudo cp etc/letsencrypt/live/your_webiste_folder/privkey.pem /var/www/directory_name
sudo cp /etc/letsencrypt/live/your_website_folder/fullchain.pem /var/www/directory_name
click here for guide about copying files and its contents

1c 为该文件夹分配权限规则。我使用ubuntu 作为我的组,因为root 拥有目录和密钥的所有权。
click this link to create a group and learn about permissions
-step a。更改拥有密钥文件的组的所有权
-注意:您需要使用root 执行此操作,键入以下cmdsudo -i
chown group_name /var/path_to_webiste/cert_directory
-step b。更改组中密钥的所有权
chown group_name /var/path_to_website/privkey.pem,
chown group_name /var/path_to_website/fullchain.pem,

1d 检查权限是否应用成功 ls -l
-下面第 3 行是目录对 root 权限的示例
- 第 4 行下面是目录对 group_name (ubuntu) 的权限示例。你想在你的代码中看到这一行。

root@ip-123-45-67-890:/var/www# ls -l
total 8
drwxr-xr-x 6 root   root   4096 Oct 20 23:50 directory_name
drwxr-xr-x 2 ubuntu ubuntu 4096 Oct 20 16:10 directory_name

Click here to learn more


2.编辑 app.jsserver.js 以连接到 HTTPS 服务器,而不是 HTTP
注意:当您在 @ 中提供 SSL 证书目录的位置路径时app.jsserver.js 中的 987654364@ 文件夹,Node 将无法看到它们,这就是您需要分配权限的原因。

App.js:

   //imports
   ......
    
    //use node over secure server
    const https = require("https"),
        fs = require("fs");
    
    const sslServer =  https.createServer (
    {
      key: fs.readFileSync('/var/path_to_privkey.pem'),
      cert: fs.readFileSync('/var/path_to_fullchain.pem'),
    },
    app  <---MAKE SURE TO PASS APP IN
    )
    
   ......
   ......
   
sslServer.listen(3000, () => {
  console.log(`Express running PORT 3000 working!`)
});

Click here for a walkthrough process for above app.js code

  1. 分配防火墙权限规则以允许通过命令ufw 允许来自app.js 文件即3001port
    -注意:如果您尝试连接到port 并且遇到超时,那么您的 apache 防火墙设置不允许该端口通过,这就是您需要编辑 apache 防火墙权限的原因 sudo ufw allow 3001

  2. 编辑 000-default.confwebsite.com.confwebsite.com-le-ssl 文件以从 HTTP 转发到 HTTPS。 -注意:website.com.conf-le-sslcertbotletsencrypt生成

000-default.conf:

<VirtualHost *:80>
        ServerName website.com
        ServerAlias www.website.com
        DocumentRoot /var/www/website.com

        ProxyPreserveHost On
        ProxyRequests Off
        ProxyPass /get-email https://1.234.567.890:3001/
        ProxyPassReverse /get-email https://1.234.567.890:3001/

        ErrorLog ${APACHE_LOG_DIR}/error.log
        CustomLog ${APACHE_LOG_DIR}/access.log combined
</VirtualHost>

website.com.conf:

<VirtualHost *:80>
    ServerName website.com
    ServerAlias www.website.com
    DocumentRoot /var/www/aws.backend-dg.com

    ErrorLog ${APACHE_LOG_DIR}/error.log
    CustomLog ${APACHE_LOG_DIR}/access.log combined

    ProxyPreserveHost Off
    ProxyRequests Off
    ProxyPass / http://1.234.567.890:3001/
    ProxyPassReverse / https://1.234.567.890:3001/

    RewriteEngine on
    RewriteCond %{SERVER_NAME} =aws.backend-dg.com [OR]
    RewriteCond %{SERVER_NAME} =3.144.239.224:3001 [OR]
    RewriteCond %{SERVER_NAME} =aws.backend-dg.com:3001 [OR]
    RewriteCond %{SERVER_NAME} =www.aws.backend-dg.com
    RewriteRule ^ https://%{SERVER_NAME}%{REQUEST_URI} [END,NE,R=permanent]
</VirtualHost>

website.com-le-ssl.conf:

<IfModule mod_ssl.c>
<VirtualHost *:443>
  ServerName website.com
  ServerAlias www.website.com
  DocumentRoot /var/www/website.com

  SSLProxyEngine On
  ProxyPass /get-email http://1.234.567.890:3001/
  ProxyPassReverse /get-email https://1.234.567.890:3001/
  ProxyPreserveHost Off
  ProxyRequests Off

  SSLEngine On
  SSLCertificateFile /etc/letsencrypt/live/website.com/fullchain.pem
  SSLCertificateKeyFile /etc/letsencrypt/live/website.com/privkey.pem
</VirtualHost>
</IfModule>

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2018-12-04
    • 1970-01-01
    • 1970-01-01
    • 2017-04-23
    • 2020-06-18
    • 2018-08-20
    • 2010-11-04
    • 2015-02-12
    相关资源
    最近更新 更多