Node.js https 服务器:无法监听端口 443 - 为什么?
Node.js https 服务器:无法监听端口 443 - 为什么?
我在Node中首次创建了一个HTTPS服务器,代码(见下文)可以在随机端口(如6643)上工作,但在443端口上无法工作。我得到了以下错误:\n
[调试][服务器]: 初始化... [调试][控制中心]: 应用程序已初始化... events.js:72 throw er; // 未处理的'错误'事件 ^ 错误:listen EACCES at errnoException (net.js:904:11) at Server._listen2 (net.js:1023:19) at listen (net.js:1064:10) at Server.listen (net.js:1138:5) at Object.module.exports.router (/home/ec2-user/Officeball/Versions/officeball_v0.0.5/server/custom_modules/server.js:52:5) at Object.(/home/ec2-user/Officeball/Versions/officeball_v0.0.5/server/control_center.js:15:59) at Module._compile (module.js:456:26) at Object.Module._extensions..js (module.js:474:10) at Module.load (module.js:356:32) at Function.Module._load (module.js:312:12)
\n这是在Amazon Linux EC2服务器上的情况。据我了解,一旦我将域名的DNS A名称记录设置为服务器的IP,当用户搜索https://mydomain.com时,浏览器将在端口443上查找我的服务器的IP,这是HTTPS流量的标准端口。\n所以我理解我需要通过443端口提供https内容。\n我做错了什么?\n
\n这是我的服务器代码:\ncontrol_center.js(初始化)\n
/* 控制中心 */ //定义全局变量 preloaded = {}; //获取工作路径 var dirPath = process.cwd(); //引入自定义模块 var debug = new (require(dirPath + "/custom_modules/debug"))("控制中心"); var socket = require(dirPath + "/custom_modules/socket")(4546); // ! 这是相关的代码行 var server = require(dirPath + "/custom_modules/server").router(443); //应用程序初始化 debug.log("应用程序已初始化...");
\nserver.js\n
/* 服务器 */ //引入NPM模块 var fs = require('fs'), https = require('https'), url = require('url'), path = require('path'); //获取工作路径 var dirPath = process.cwd(); //引入自定义模块 //省略! var debug = new (require(dirPath + "/custom_modules/debug"))("服务器"); //预加载请求 var preload = require(dirPath + '/custom_modules/preload').init(); //初始化模块 debug.log("已初始化..."); //定义模块变量 var options = { key: fs.readFileSync('SSL/evisiion_private_key.pem'), cert: fs.readFileSync('SSL/evisiion_ssl_cert.pem') }; //监听路径请求 //将请求路由到服务器 module.exports.router = function(port) { https.createServer(options, function(req, res) { //省略! }).listen(port); };
Node.js https服务器无法监听端口443的原因是,在Linux和其他类Unix的操作系统上,服务必须以root用户运行,才能绑定到小于1024的端口号。
解决方法是在开发环境中使用高端口号(如8080),在生产环境中使用像Nginx这样的真正的Web服务器来提供静态内容,并将其他所有内容反向代理到Node应用程序。这样做可以避免以root用户运行应用程序的问题。
你可以使用Nginx来处理静态文件,并将其他内容反向代理到Node应用程序的另一个端口上。下面是一个示例配置文件:
server { listen 443; server_name example.com; client_max_body_size 50M; access_log /var/log/nginx/access.log; error_log /var/log/nginx/error.log; location /static { root /var/www/mysite; } location / { proxy_pass http://127.0.0.1:8000; } }
上述配置假设你的Web应用程序可以通过端口443访问,并且正在运行在端口8000上。如果请求的路径匹配/static文件夹,则从/var/www/mysite/static目录中提供静态文件。否则,Nginx将请求转发到运行在端口8000上的应用程序,可以是Node.js应用程序、Python应用程序或其他应用程序。
使用Nginx作为反向代理解决了该问题,因为应用程序可以通过端口443访问,而不必实际绑定到该端口。
需要注意的是,以root用户身份运行此类服务通常是不明智的做法。这将给予可能存在漏洞的应用程序和所使用的任何NPM模块root访问权限。将其放在Nginx之后可以避免以root用户运行,而且Nginx非常稳定、经过充分测试,并且具有良好的性能和缓存能力。此外,Nginx通常在提供静态内容方面速度更快。
可以使用sudo
命令作为解决方案,但这通常被认为是一个不好的做法,因为它会增加应用程序和NPM模块受到攻击的风险。
如果不需要静态文件,可以使用iptables解决端口问题,而无需以root权限运行。如果需要静态文件,最好使用Nginx来处理静态文件,并将其他内容反向代理到Node.js应用程序的端口上。
可以使用process.setgid()
和process.setuid()
方法在监听端口后降低root权限。
使用Nginx作为反向代理可以更轻松地实现压缩响应,并且Nginx已经为你处理了HTTP头,可以更容易地利用浏览器对静态文件的缓存。
在性能方面,Nginx通常被认为比Node.js更快速地提供静态文件。即使Node.js可以做到同样的速度,但需要自己实现相关功能。
Express的创建者明确建议使用反向代理来处理静态文件,而不是使用Express本身来提供静态文件。
还有一些工具,如setcap
和authbind
,可以允许非root进程设置端口。
无论是否可能,将应用程序放在Nginx之后通常会更高效和更安全。
需要注意的是,虽然在Linux上服务需要以root用户运行才能绑定到小于1024的端口,但这并不意味着一定要以root用户运行服务,这只是一个近似的说法。