Reputation: 173
We're running an instance of Metabase on a App Engine Flexible Custom Runtime with a Dockerfile based on openjdk:8. Currently it allows access on http://[metabase-project].appspot.com/ and https://[metabase-project].appspot.com/. I'd like to force SSL by having all http traffic redirected to https.
The Dockerfile looks something like this:
FROM openjdk:8
ADD https://dl.google.com/cloudsql/cloud_sql_proxy.linux.amd64 ./cloud_sql_proxy
ADD http://downloads.metabase.com/v0.21.1/metabase.jar ./metabase.jar
CMD ./cloud_sql_proxy -instances=$INSTANCE=tcp:$MB_DB_PORT -dir=/cloudsql & java -jar ./metabase.jar
Our app.yaml looks like:
service: metabase
runtime: custom
env: flex
In a normal App Engine app.yaml file, I'd want to add:
handlers:
- url: [something]
secure: always
But in the custom runtime we don't have access to handlers like this. Is there a way to configure the Flexible runtime to perform the redirect for all traffic?
Upvotes: 17
Views: 7823
Reputation: 6424
Here's the Node.js Express code I use:
// set the env variable REQUIRE_HTTPS=1 to enable this middleware
.use(function(req, res, next) {
// Redirect HTTP to HTTPS
if (!process.env.REQUIRE_HTTPS) return next();
if (req.headers["x-forwarded-proto"] === "https") return next();
if (req.protocol === "https") return next();
res.redirect(301, `https://${req.hostname}${req.url}`);
})
Put it as the first middleware in your Express app.
This code assumes that you're using standard ports for http/https, as is the case when you're on AppEngine.
Upvotes: 0
Reputation: 1649
Use the following code
app.use (function (req, res, next) {
var schema = (req.headers['x-forwarded-proto'] || '').toLowerCase();
if (schema === 'https') {
next();
} else {
res.redirect('https://' + req.headers.host + req.url);
}
});
Upvotes: 0
Reputation: 2239
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.
Upvotes: 9
Reputation: 66
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 of req.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:
Upvotes: 4
Reputation: 2023
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.
Upvotes: 7
Reputation: 7866
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!
Upvotes: 8