Force SSL on App Engine Flexible Environment Custom Runtime
Late to answer, but I had to struggle a lot in order to do this.
I followed various links which mentioned the following code,
app.use(function(req, res, next) {
if(!req.secure) {
return res.redirect(['https://', req.get('Host'), req.url].join(''));
}
next();
});
This might work in other cloud vendors.
But in GCP as rightly mentioned by @zengabor, our app will be running behind an nginx reverse proxy which terminates the SSL connection, we need to check the X-FORWARDED-PROTO
which can be done by the following code,
app.use(function(req, res, next) {
if(req.headers['x-forwarded-proto'] && req.headers['x-forwarded-proto'] === "http") {
return res.redirect(['https://', req.get('Host'), req.url].join(''));
}
next();
});
Just adding my answer as after reading @zengabor's code I had to search again on how to achieve it. So above is the readymade code which will work.
App Engine Flex doesn't support handlers, at all: https://cloud.google.com/appengine/docs/flexible/java/upgrading#appyaml_changes
If you need https:// redirects, you need to do it from within your application. Sorry!
Since your app (env: flex
in app.yaml) is running behind an nginx reverse proxy which terminates the SSL connection, you need to check the X-FORWARDED-PROTO
header which will be either http
or https
. If it’s http
then you can do the redirect.
This is what worked for me. In my case using Loopback based NodeJS application running in Cloud Sites App Engine flexible environment.
-
Create a middleware, for example
server/middleware/https-redirect.js
with the following code:/** * Create a middleware to redirect http requests to https * @param {Object} options Options * @returns {Function} The express middleware handler */ module.exports = function(options) { options = options || {}; var httpsPort = options.httpsPort || 443; return function(req, res, next) { if (req.protocol != 'https' && process.env.NODE_ENV !== 'development') { var parts = req.get('host').split(':'); var host = parts[0] || '127.0.0.1'; return res.redirect('https://' + host + ':' + httpsPort + req.url); } next(); }; };
(based on the step 8 in the post http://www.jonxie.com/blog/2014/11/12/setting-up-loopback-to-use-https-and-ssl-certificates/ but modified to use
req.protocol
instead ofreq.secure
, also will only redirect if not running in development mode) -
Modify the file
server/server.js
to request:var httpsRedirect = require('./middleware/https-redirect');
-
An then, after the boot line:
var httpsPort = app.get('https-port'); app.use(httpsRedirect({httpsPort: httpsPort})); app.set('trust proxy', true)
Setting app.set('trust proxy', true)
will let the req.protocol read the X-Forwarded-Proto
header.
References:
- http://expressjs.com/es/api.html#req.protocol
- http://expressjs.com/en/guide/behind-proxies.html
- http://www.jonxie.com/blog/2014/11/12/setting-up-loopback-to-use-https-and-ssl-certificates/