我已设置 Node.js 服务器,并尝试在 Apache 上使用我的 Let's Encrypt 证书进行 HTTPS 传输。以下是我设置的相关代码:
var fs = require('fs'),
https = require('https'),
express = require('express'),
options = {
key: fs.readFileSync('/etc/letsencrypt/live/www.mysite.com/privkey.pem'),
cert: fs.readFileSync('/etc/letsencrypt/live/www.mysite.com/fullchain.pem'),
ca: fs.readFileSync('/etc/letsencrypt/live/www.mysite.com/chain.pem')
}, ...
当我尝试启动脚本时,出现此错误:
Error: EACCES: permission denied, open '/etc/letsencrypt/live/www.mysite.com/privkey.pem'
这是因为只有 root 所有者才拥有 SSL 的 Let's Encrypt 目录和文件,目前我在 Apache 上的 30 多个常规网站都在使用 SSL。我正在尝试为一个网站设置一个 Node App。我的 node app.js 项目文件归 mysite1:mysite1 所有,我知道以非 root 用户身份运行 node app 应该更安全(例如“mysite1”)。
什么是使我的 Let's Encrypt HTTPS 与 Node.js 应用程序(在 Apache 上)安全地协同工作的正确方法,而不必授予我的 /etc/letsencrypt 目录 755 权限?
编辑-澄清:
Node.js 和 Apache 并行运行。在我的网站的 virtualHost .conf 文件中,443 DocumentRoot 是 /home/mysite1/mysite1.com ,这就是我安装 Let's Encrypt SSL 的目的。
我的 Node.js 应用程序设置在 /home/mysite1/app 中。在网站上,我使用 socket.io 作为站点范围的聊天室,并且它可以完美地连接/运行,如下所示(如果应用程序以 root 用户身份启动),不需要 ProxyPass:
<script src="//www.mysite1.com:3000/socket.io/socket.io.js"></script>
<script>var socket = io('https://www.mysite1.com:3000');</script>
当我以非 root 用户身份运行应用程序时(出于安全目的),我看到的唯一错误是我的节点应用程序在尝试访问/配置 SSL 文件时出现权限错误。我具体应该怎么做,我不太清楚如何在 Apache“后面”运行它,或者是否有更简单的解决方案?
似乎必须有一个更简单的解决方案,也许 node.js 以 root 身份运行以获取 SSL 数据并在将其交给用户之前使服务器运行,就像 Apache 一样?
编辑2:
根据 Michael 和 ezra-s 的建议,我在 Google 上搜索了一段时间,并做了一些修改,但还是无法正常工作。在 Apache 中,我做了类似的事情:
<VirtualHost *:443>
ServerAlias mysite1.com
DocumentRoot /home/mysite1/mysite1.com
DirectoryIndex index.html index.php
<Directory /home/mysite1/mysite1.com>
.. web config stuff
</Directory>
ProxyRequests Off
ProxyPreserveHost On
ProxyVia Full
<Proxy *>
Require all granted
</Proxy>
<Location /node>
ProxyPass http://127.0.0.1:3000
ProxyPassReverse http://127.0.0.1:3000
</Location>
SSLEngine on
Include /etc/letsencrypt/options-ssl-apache.conf
SSLCertificateFile /etc/letsencrypt/live/www.letshangout.com/fullchain.pem
SSLCertificateKeyFile /etc/letsencrypt/live/www.letshangout.com/privkey.pem
</VirtualHost>
在我的 node app.js 项目文件中,我删除了 require('https') 和证书选项,并用“http”包替换它并尝试初始化脚本。
在我的网站的一个页面上,我有一些脚本尝试加载 socket.io 并连接到节点应用程序:
<script src="https://www.mysite1.com/node/socket.io/socket.io.js"></script>
<script>var socket = io('https://www.mysite1.com/node/');</script>
当我加载页面时,出现 500 错误,并且脚本无法加载。我应该在 Apache 配置或脚本 URL 中更改什么?我以前从未在节点中使用过代理,这是我的第一个节点应用程序。
解决方案:
我明白了,这是需要涉及 Web 套接字和 JavaScript 的其他事情的组合:
1)用于处理 websockets 的 Apache 配置https://stackoverflow.com/a/41685748/2317571
2)客户端的 JavaScript 套接字连接配置https://stackoverflow.com/questions/22919276/how-to-connect-socket-io-through-a-reverse-proxy
3)(额外提示):感谢 Michael 和 ezra-s 的建议,他们将 node 应用程序置于 Apache 后面,我可以使用 ufw 防火墙并将 node/socket.io 端口 3000 锁定到本地主机 - 向世界开放的端口(和安全漏洞)少了一个。希望这些信息可以帮助其他人。
答案1
1. 在端口上单独运行 Node.js 应用程序。
2. 对其执行反向代理。
笔记:Node.js 应用程序与 Apache 之间的连接将使用 HTTP。但是,它只会在“localhost”级别进行。因此,这样就没问题了。
虚拟主机配置:
<VirtualHost *:443>
ServerName nodeapp.com
ServerAdmin webmas@localhost
DocumentRoot /var/www/nodeapp
SSLEngine on
SSLCertificateFile /path/to/cert
SSLCertificateKeyFile /path/to/key
ProxyRequests off
ProxyPass "/" "http://127.0.0.1:node_app_port/"
ProxyPassReverse "/" "http://127.0.0.1:node_app_port/"
ErrorLog ${APACHE_LOG_DIR}/nodeapp_error.log
CustomLog ${APACHE_LOG_DIR}/nodeapp_access.log combined
</VirtualHost>