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?
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!
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:
- 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/
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.