I have an app which is quite normal Express app - simple server logic, views, lots of client-side JS. I have to do many AJAX requests. Some of them need to be secured by HTTPS protocol (some needn't).
So, my server should work with both HTTP and HTTPS. It should also work o both the local machine (ran with nodemon normally) and on Heroku.
As far as I understood, Heroku gives you a single port (process.env.PORT) you can listen to, and handles all requests through the proxy (so, you app is listening to this port and not bothering about the proto - right?)
So, am I getting this right - I should have some different code for dev machine and Heroku?
Like
...
app = express()
...
if process.env.NODE_ENV == 'production'
app.listen(process.env.PORT)
else
https = require('https')
http = require('http')
http.createServer(app).listen(5080) # some local port
options = {
key: fs.readFileSync('key.pem'),
cert: fs.readFileSync('cert.pem') # my self-signed files
}
https.createServer(options, app).listen(5443) # some different local port
Is it the proper way to deal with this?
We will perform HTTP to HTTPS redirection by creating an Express middleware function [ 1] and then, inside that function, write the redirection code that will force Express to use HTTPS. The middleware function provides access to the Express req and res objects and next function that we will need.
For the Coffeescript-challenges, here is a version of Guard's answer converted to Javascript. I took a different approach to splitting up the if else statements.
var express = require('express');
var http = require('http');
var https = require('https');
var fs = require('fs');
var privateKey = fs.readFileSync('./config/localhost.key').toString();
var certificate = fs.readFileSync('./config/localhost.crt').toString();
var options = {
key : privateKey
, cert : certificate
}
var app = express();
// Start server.
var port = process.env.PORT || 3000; // Used by Heroku and http on localhost
process.env['PORT'] = process.env.PORT || 4000; // Used by https on localhost
http.createServer(app).listen(port, function () {
console.log("Express server listening on port %d in %s mode", this.address().port, app.settings.env);
});
// Run separate https server if on localhost
if (process.env.NODE_ENV != 'production') {
https.createServer(options, app).listen(process.env.PORT, function () {
console.log("Express server listening with https on port %d in %s mode", this.address().port, app.settings.env);
});
};
if (process.env.NODE_ENV == 'production') {
app.use(function (req, res, next) {
res.setHeader('Strict-Transport-Security', 'max-age=8640000; includeSubDomains');
if (req.headers['x-forwarded-proto'] && req.headers['x-forwarded-proto'] === "http") {
return res.redirect(301, 'https://' + req.host + req.url);
} else {
return next();
}
});
} else {
app.use(function (req, res, next) {
res.setHeader('Strict-Transport-Security', 'max-age=8640000; includeSubDomains');
if (!req.secure) {
return res.redirect(301, 'https://' + req.host + ":" + process.env.PORT + req.url);
} else {
return next();
}
});
};
Well, community looks quite dead these days (hope I'm wrong)
The answer is:
a) yes, this is the way to deal with it
b) the way to check if you are in secure mode or not depends on the environment as well:
if process.env.NODE_ENV == 'production'
is_secure = (req) ->
req.headers['x-forwarded-proto'] == 'https'
else
is_secure = (req) -> req.secure
ADD If you wish to force HTTPS:
redirect_to_https = (req, res, next) ->
if not is_secure(req)
res.redirect config.SECURE_DOMAIN + req.url
else
next()
app
.use(redirect_to_https)
You can use app.enable('trust proxy')
, then req.secure
boolean (http/https) works also on Heroku, or behind any compatible SSL Termination proxy.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With