Listen on HTTP and HTTPS for a single express app

65,804

Solution 1

You can share the implementation via something like:

var register = function (app) {
    // config middleware
    app.configure({

    });

    // config routes
    app.get(...);
};

var http = express.createServer();
register(http);
http.listen(80);

var https = express.createServer({ key: /* https properties */ });
register(https);
https.listen(443);

Solution 2

To enable your app to listen for both http and https on ports 80 and 443 respectively, do the following

Create an express app:

var express = require('express');
var app = express();

The app returned by express() is a JavaScript function. It can be be passed to Node’s HTTP servers as a callback to handle requests. This makes it easy to provide both HTTP and HTTPS versions of your app using the same code base.

You can do so as follows:

var express = require('express');
var https = require('https');
var http = require('http');
var fs = require('fs');
var app = express();

var options = {
  key: fs.readFileSync('/path/to/key.pem'),
  cert: fs.readFileSync('/path/to/cert.pem'),
  ca: fs.readFileSync('/path/to/ca.pem')
};

http.createServer(app).listen(80);
https.createServer(options, app).listen(443);

For complete detail see the doc

Solution 3

As a possible update to this question, you might want to check out the changes here for express 3. The change document says:

The return value of express() is a JavaScript Function, encapsulating everything that makes an Express app tick. This means you can easily setup HTTP and HTTPS versions of your application by passing it to node's http.createServer() and https.createServer():

In Express 3, express.createServer() is now express()

Here is a complete example for express 3:

var fs = require('fs')
    , https = require('https')
    , http = require('http')
    , express = require('express')
    , keys_dir = 'keys/'
    , server_options = {
        key  : fs.readFileSync(keys_dir + 'privatekey.pem'),
        ca   : fs.readFileSync(keys_dir + 'certauthority.pem'),
        cert : fs.readFileSync(keys_dir + 'certificate.pem')
      }
    , app = express();
app.configure(function(){
  app.use(express.cookieParser());
  app.use(express.bodyParser());
  app.use(express.methodOverride());
  app.use(express.session( { secret: '' } ));
  app.use(app.router);
});
app.configure('development',function(){
  app.use(express.static(__dirname + '/public'));
  app.use(express.errorHandler({dumpExceptions: true, showStack:true}));
  app.set('view options', { pretty: true });
});
app.get('/', function(req, res){
  res.send('Hello World!');
});
https.createServer(server_options,app).listen(7000);
http.createServer(app).listen(8000);

Solution 4

You can use express and https in same port.

this works for me.

const express=require('express');
const app=express();
const cors=require('cors');
const path=require("path");
const routes=require('./routes/api');
const routerComplain=require('./routes/api');
const routerstores=require('./routes/api');
const routerstock=require('./routes/api');
const routerreport=require('./routes/api');
const routeritem=require('./routes/api');
const bodyParser=require('body-parser');
const routerRegister=require('./routes/api');
const mongoose=require('mongoose');
var server = require('http').Server(app);
var io = require('socket.io')(server);
require("dotenv").config();

mongoose.connect('mongodb://@@@@@@@@@@@@@@@@@',{ useNewUrlParser: true },(err)=>{
    if(!err){
        console.log('db connected')
    }else{
        console.log('error in db')
    }
});

mongoose.Promise = global.Promise;
app.use(express.static('public'));
app.use(bodyParser.json());
app.use(cors({credentials: true, origin:'http://localhost:3000'}));
app.use(express.static(path.join(__dirname, "client", "build")))

app.use('/reg',routes);
app.use('/complain',routerComplain);
app.use('/register',routerRegister);
app.use('/stores',routerstores);
app.use('/reports',routerreport);
app.use('/stock',routerstock);
app.use('/items',routeritem);

app.get("*", (req, res) => {
    res.sendFile(path.join(__dirname, "client", "build", "index.html"));
});

io.on('connection', function (socket) {
    socket.emit('news', { hello: 'world' });
    socket.on('my other event', function (data) {
      console.log(data);
    });
  })

const port = process.env.port||4000;

server.listen(port,function(){
    console.log('now listening for request');
});

Solution 5

If you want to use the traditional two ports, one of the above solutions probably works, but using httpolyglot, you can really easily have http and https on the same port with the same middlewares.

https://github.com/mscdex/httpolyglot

Here's some skeleton code that worked for me:

var express = require('express');
var fs = require('fs');
var httpolyglot = require('httpolyglot');
var app = express();

const options = {
    key: fs.readFileSync("/etc/ssl/certs/key"),
    cert: fs.readFileSync("/etc/ssl/certs/cer.cer")
};

httpolyglot.createServer(options, app).listen(port);

and if you want http -> https forwarding, you can just add this middleware function before the createServer() call:

app.use(function(req, res, next) {
    if (!req.secure ) {
            res.redirect (301, 'https://' + req.hostname + ':port' + req.originalUrl);
    }
    next();
});

This can be set up on a custom port

Share:
65,804
Jazz
Author by

Jazz

Working on F4 Map and Bien'ici

Updated on December 14, 2020

Comments

  • Jazz
    Jazz over 3 years

    Can I create an Express server listening on both HTTP and HTTPS, with the same routes and the same middlewares?

    Currently I do this with Express on HTTP, with stunnel tunneling HTTPS to Express, but I prefer a pure Node solution.

    I can do it with this code, but using the handle method that is marked as private:

    var express = require( 'express' )
        , https = require("https")
        , fs = require( 'fs' );
    
    var app = express.createServer();
    // init routes and middlewares
    app.listen( 80 );
    
    var privateKey = fs.readFileSync( 'privatekey.pem' ).toString();
    var certificate = fs.readFileSync( 'certificate.pem' ).toString();
    var options = {key: privateKey, cert: certificate};
    https.createServer( options, function(req,res)
    {
        app.handle( req, res );
    } ).listen( 443 );
    
  • Jazz
    Jazz over 12 years
    I know how to create a HTTPS server, but not a server responding both on HTTP and HTTPS.
  • Declan Cook
    Declan Cook over 12 years
    Did you read the other post? There is an example in the post. You create 2 server instances and make one listen on port 80 and one on 443, Http and Https.
  • Jazz
    Jazz over 12 years
    Yes, I read the other post: there are 2 server instances with different routes. I want the same routes for both (or only one instance listening on HTTP and HTTPS).
  • Declan Cook
    Declan Cook over 12 years
    you could declare the route functions separately and then use them to declare the route for both servers. Other than that option I don't know of a simple way to do what you are trying to do. Why would you need to serve the same content over both http and https?
  • Jazz
    Jazz over 12 years
    Because this server content will be included in HTTP and HTTPS sites. I can declare the routes and middlewares for both servers, but I hoped I could do better.
  • Declan Cook
    Declan Cook over 12 years
    Not that I can think of off the top of my head. Sorry
  • Catalin MUNTEANU
    Catalin MUNTEANU about 11 years
    This solution is now deprecated. Is there a newer solution?
  • gcochard
    gcochard over 10 years
    It's preferable to answer a question using the same language that the asker used. I have taken the liberty of translating the coffeescript to vanilla JS.
  • Amitava
    Amitava over 10 years
    I started with listening to both http and https but then I scraped the idea and used nginx to do request handling (both http and https) and use http only in my node app. Much easier life in production, dev and testing.
  • paulsm4
    paulsm4 about 8 years
    @CMN - See cmd's solution below. It works with current versions of Node (v4.4.2) and Express (4.13.4)
  • Nick Manning
    Nick Manning over 2 years
    Neat...is there a benefit to putting them on the same port?