Node.js https server: Can't listen to port 443

2019-03-20 03:17发布

问题:

I'm creating a an HTTPS server for the first time in Node, and the code (see below) works for a random port like 6643 but on port 443, it won't work. I get this error:

[Debug][Server]: Initialized...
[Debug][Control Center]: Application initialized...

events.js:72
        throw er; // Unhandled 'error' event
              ^
Error: 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.<anonymous> (/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)

This is on an Amazon Linux EC2 server. It's my understanding that once I set my domain's DNS A Name Record to the server's IP, when a user searches https://mydomain.com, the browser will look up my server's IP at port 443, which is supposedly the standard port for HTTPS traffic.

So my understanding is that I need to serve https content via port 443.

What am I doing wrong?


Here's my server code:

control_center.js (init)

/* Control Center */

//DEFINE GLOBALS

preloaded = {};

//GET DIRECT WORKING PATH

var dirPath = process.cwd();

//REQUIRE CUSTOM MODULES 

var debug = new (require(dirPath + 
        "/custom_modules/debug"))("Control Center");
var socket = require(dirPath + 
        "/custom_modules/socket")(4546);

// ! this is the relevant line
var server = require(dirPath + "/custom_modules/server").router(443);

//APP INITIALIZE

debug.log("Application initialized...");

server.js

/* Server */

//REQUIRE NPM MODULES

var fs      = require('fs'), 
    https   = require('https'), 
    url     = require('url'), 
    path    = require('path');

//GET DIRECT WORKING PATH

var dirPath = process.cwd();

//REQUIRE CUSTOM MODULES

//Snip!

var debug = new (require(dirPath + 
        "/custom_modules/debug"))("Server");

//Preload requests

var preload = require(dirPath + 
        '/custom_modules/preload').init();

//INIT MODULE 

debug.log("Initialized...");

//DEFINE MODULE VARIABLES

var options = {
  key: fs.readFileSync('SSL/evisiion_private_key.pem'),
  cert: fs.readFileSync('SSL/evisiion_ssl_cert.pem')
};

//LISTEN FOR PATH REQUESTS

//route requests to server
module.exports.router = function(port) {
    https.createServer(options, function(req, res) {

        //Snip!

    }).listen(port);
};

回答1:

On Linux (and, I believe, most other Unix-like operating systems), a service has to run as root to be able to bind to a port numbered less than 1024.

I've just verified it on a Node app I had lying around, and I saw exactly the same error, line for line identical barring the file paths, when I changed the port from 5000 to 443.

In development, most people will run the dev server on a higher-numbered port such as 8080. In production, you might well want to use a proper web server such as Nginx to serve static content and reverse proxy everything else to your Node app, which makes it less of an issue since Nginx can be quite happily run as root.

EDIT: As your use case requires serving some static content, then you may want to use a web server such as Nginx or Apache to handle the static files, and reverse proxy to another port for your dynamic content. Reverse proxying is quite straightforward with Nginx - here's a sample config file:

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;
    }
}

This assumes your web app is to be accessible on port 443, and is running on port 8000. If the location matches the /static folder, it is served from /var/www/mysite/static. Otherwise, Nginx hands it off to the running application at port 8000, which might be a Node.js app, or a Python one, or whatever.

This also quite neatly solves your issue since the application will be accessible on port 443, without having to actually bind to that port.