First, let me see if I can clarify the problem. You are limited to one (1) node.js process, but this process can listen on two (2) network ports, both 80 and 443, right? (When you say one server, it is not cleared if you mean one process or only one network port).
Given this limitation, it seems that the problem is for reasons that you do not provide, somehow your clients are connecting to the wrong port. This is a bizarre extreme case, because by default clients will send HTTP requests to port 80 and HTTPS to port 443. And when I say "default", I mean if certain ports are not specified in the URLs. Therefore, unless you explicitly use cross-URLs such as http: //example.com-00-0043 and https://example.com:80 , you really shouldn't have cross-traffic coming to your site. But since you asked the question, I think you should have it, although I'm sure you are using non-standard ports, not the default 80/443.
So, for the background: YES, some web servers handle this pretty well. For example, if you run http://example.com-00-0043 on nginx, it will respond to an HTTP 400 "Bad Request" response indicating "A simple HTTP request has been sent to the HTTPS port." YES, you can listen to both 80 and 443 from the same node.js. process. You just need to create 2 separate instances of express.createServer() so that there are no problems. Here's a simple program to demonstrate the processing of both protocols.
var fs = require("fs"); var express = require("express"); var http = express.createServer(); var httpsOptions = { key: fs.readFileSync('key.pem'), cert: fs.readFileSync('cert.pem') }; var https = express.createServer(httpsOptions); http.all('*', function(req, res) { console.log("HTTP: " + req.url); return res.redirect("https://" + req.headers["host"] + req.url); }); http.error(function(error, req, res, next) { return console.log("HTTP error " + error + ", " + req.url); }); https.error(function(error, req, res, next) { return console.log("HTTPS error " + error + ", " + req.url); }); https.all('*', function(req, res) { console.log("HTTPS: " + req.url); return res.send("Hello, World!"); }); http.listen(80);
And I can verify this via cURL as follows:
$ curl --include --silent http://localhost/foo HTTP/1.1 302 Moved Temporarily X-Powered-By: Express Content-Type: text/html Location: https://localhost/foo Connection: keep-alive Transfer-Encoding: chunked <p>Moved Temporarily. Redirecting to <a href="https://localhost/foo">https://localhost/foo</a></p> $ curl --include --silent --insecure https://localhost:443/foo HTTP/1.1 200 OK X-Powered-By: Express Content-Type: text/html; charset=utf-8 Content-Length: 13 Connection: keep-alive Hello, World!%
And showing a redirect from HTTP to HTTPS ...
curl --include --silent --location --insecure 'http://localhost/foo?bar=bux' HTTP/1.1 302 Moved Temporarily X-Powered-By: Express Content-Type: text/html Location: https:
So, this will work to serve both protocols for the normal case and redirect correctly. However, crosses do not work at all. I believe that a request with cross-references to the express server will not be redirected through the middleware stack, since it will be considered as an error from the very beginning and will not even be able to correctly process the URI request, which is necessary for sending it through the middleware chain route. The express stack did not even receive them, I think, because they are not valid requests, therefore they are ignored somewhere in the node TCP stack. You can probably write a server to do this, and there may already be a module there, but you will have to write it right at the TCP level. And you will have to detect a normal HTTP request in the first piece of client data that gets to the TCP port and connect this connection to the HTTP server instead of the usual TLS acknowledgment.
When I do this, my explicit error handlers do NOT receive the call.
curl --insecure https://localhost:80/foo curl: (35) Unknown SSL protocol error in connection to localhost:80 curl http://localhost:443/foo curl: (52) Empty reply from server