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!
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.jswith 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.protocolinstead ofreq.secure, also will only redirect if not running in development mode)Modify the file
server/server.jsto 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:
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.
来源:https://stackoverflow.com/questions/41944776/force-ssl-on-app-engine-flexible-environment-custom-runtime