我如何 运行 节点和同一台服务器上的 apache 允许用户通过 https 访问 api?
How can I run node and apache on the same server to allow the user to access api through https?
我运行在同一台服务器上连接Node和Apache,其中node是后端服务器,Axios请求从前端收集用户数据。
我使用 Apache 通过 certbot
申请了 SSL 证书并成功了。我正在尝试部署节点后端以访问我的 endpoint
即 (website.com/endpoint)
.
我可以看到位于网站文件夹中的测试 index.html
。当我尝试 aws.website.com/endpoint
时,出现服务器超时和 404 未找到错误。
我的应用程序在 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;
答案是保护节点后端服务器,以便用户留在安全的 HTTPS
地址上。您可以通过将 SSL
键分配给节点服务器来完成此操作。然后编辑 app.js 文件以连接到 HTTPS
,而不是 HTTP
。上面的 app.js
仅连接到 HTTP
。所以这需要修复。最后,将 Apache
虚拟主机中的反向代理编辑为 fwd HTTP
到 HTTPS
.
在我的例子中,前端通过来自 let's encrypt (certbot
) 的 HTTPS
SSL
证书是安全的,即 https://website.com
,但后端不安全,所以当我试图去 https://websote/endpoint
时出现错误。
这是因为后端 app.js
文件在需要连接到 HTTPS
.
时连接到 HTTP
服务器
注意:如果你有一个安全的 website/app 并且你向一个非安全的 HTTP
地址发出 Axios 请求那么你将得到一个 cors
错误指出您需要将 HTTP
更改为 HTTPS
。您可以通过使 node.js 服务器安全来做到这一点。
细分如下:
1a。在节点文件夹中创建一个单独的目录来保存证书。 sudo mkdir directory_name
1b。 *将 SSL
证书从 Apache 服务器复制到节点服务器目录。
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
-步骤a。更改拥有密钥文件的组的所有权
- 注意:您需要使用 root
执行此操作,键入以下内容 cmd
:sudo -i
chown group_name /var/path_to_webiste/cert_directory
-步骤b。更改组中密钥的所有权
chown group_name /var/path_to_website/privkey.pem
,
chown group_name /var/path_to_website/fullchain.pem
,
1d 检查权限是否申请成功
ls -l
- 下面第 3 行是根目录权限的例子
- 下面第 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
2。编辑 app.js
或 server.js
以连接到 HTTPS
服务器,而不是 HTTP
注意:当您在 app.js
或 server.js
的 Node
文件夹中提供 SSL 证书目录的位置路径时,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
分配防火墙权限规则以允许您从 app.js
文件中使用的 port
,即 3001
通过命令 ufw
被允许.
-注意:如果您尝试连接到 port
并且超时,那么您的 apache 防火墙设置不允许该端口通过,这就是您需要编辑 apache 防火墙权限的原因
sudo ufw allow 3001
编辑 000-default.conf
、website.com.conf
和 website.com-le-ssl
文件以从 HTTP 转发到 HTTPS。
-注意:website.com.conf-le-ssl
是由 certbot
从 letsencrypt
生成的
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>
我运行在同一台服务器上连接Node和Apache,其中node是后端服务器,Axios请求从前端收集用户数据。
我使用 Apache 通过 certbot
申请了 SSL 证书并成功了。我正在尝试部署节点后端以访问我的 endpoint
即 (website.com/endpoint)
.
我可以看到位于网站文件夹中的测试 index.html
。当我尝试 aws.website.com/endpoint
时,出现服务器超时和 404 未找到错误。
我的应用程序在 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;
答案是保护节点后端服务器,以便用户留在安全的 HTTPS
地址上。您可以通过将 SSL
键分配给节点服务器来完成此操作。然后编辑 app.js 文件以连接到 HTTPS
,而不是 HTTP
。上面的 app.js
仅连接到 HTTP
。所以这需要修复。最后,将 Apache
虚拟主机中的反向代理编辑为 fwd HTTP
到 HTTPS
.
在我的例子中,前端通过来自 let's encrypt (certbot
) 的 HTTPS
SSL
证书是安全的,即 https://website.com
,但后端不安全,所以当我试图去 https://websote/endpoint
时出现错误。
这是因为后端 app.js
文件在需要连接到 HTTPS
.
HTTP
服务器
注意:如果你有一个安全的 website/app 并且你向一个非安全的 HTTP
地址发出 Axios 请求那么你将得到一个 cors
错误指出您需要将 HTTP
更改为 HTTPS
。您可以通过使 node.js 服务器安全来做到这一点。
细分如下:
1a。在节点文件夹中创建一个单独的目录来保存证书。 sudo mkdir directory_name
1b。 *将 SSL
证书从 Apache 服务器复制到节点服务器目录。
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
-步骤a。更改拥有密钥文件的组的所有权
- 注意:您需要使用 root
执行此操作,键入以下内容 cmd
:sudo -i
chown group_name /var/path_to_webiste/cert_directory
-步骤b。更改组中密钥的所有权
chown group_name /var/path_to_website/privkey.pem
,
chown group_name /var/path_to_website/fullchain.pem
,
1d 检查权限是否申请成功
ls -l
- 下面第 3 行是根目录权限的例子
- 下面第 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
2。编辑 app.js
或 server.js
以连接到 HTTPS
服务器,而不是 HTTP
注意:当您在 app.js
或 server.js
的 Node
文件夹中提供 SSL 证书目录的位置路径时,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
分配防火墙权限规则以允许您从
app.js
文件中使用的port
,即3001
通过命令ufw
被允许.
-注意:如果您尝试连接到port
并且超时,那么您的 apache 防火墙设置不允许该端口通过,这就是您需要编辑 apache 防火墙权限的原因sudo ufw allow 3001
编辑
生成的000-default.conf
、website.com.conf
和website.com-le-ssl
文件以从 HTTP 转发到 HTTPS。 -注意:website.com.conf-le-ssl
是由certbot
从letsencrypt
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>