Heroku的NodeJS http到https ssl强制redirect
我有一个应用程序启动并运行在与https,节点快递与英雄。 如何识别协议以强制redirect到heroku上的nodejs https?
我的应用程序只是一个简单的http服务器,它并没有(但)意识到heroku发送https请求:
/* Heroku provides the port they want you on in this environment variable (hint: it's not 80) */ app.listen(process.env.PORT || 3000);
答案是使用Heroku向前传递的'x-forward-proto'的头部,就像它代理的thingamabob一样。 (注意:它们也传递了其他几个x-variables,可能很方便, 请检查一下 )。
我的代码:
/* At the top, with other redirect methods before other routes */ app.get('*',function(req,res,next){ if(req.headers['x-forwarded-proto']!='https') res.redirect('https://mypreferreddomain.com'+req.url) else next() /* Continue to other routes if we're not redirecting */ })
感谢布兰登,只是在等待那6个小时的延迟,不让我回答自己的问题。
截至今天, 2014年10月10日 ,使用Heroku Cedar堆栈和ExpressJS〜3.4.4 ,这里是一组工作代码。
这里要记住的主要是我们正在部署到Heroku。 在encryptionstream量到达您的节点应用之前,负载均衡器会发生SSL终止。 可以使用req.headers ['x-forwarded-proto'] ==='https'来testing是否使用https进行请求。
我们不需要关心在应用程序内部拥有本地的SSL证书,就像您在其他环境中托pipe一样。 但是,如果您使用自己的证书,子域名等,您应该首先获得通过Heroku插件应用的SSL加载项。
然后,只需添加以下内容即可将HTTPS之外的任何其他内容redirect到HTTPS。 这与上面接受的答案非常接近,但是:
- 确保您使用“app.use”(对于所有操作,而不仅仅是获取)
- 显式地将forceSsl逻辑外部化为一个声明的函数
- 不要在“app.use”中使用“*” – 当我testing时,这实际上失败了。
- 在这里,我只想在生产中使用SSL。 (根据您的需要更改)
码:
var express = require('express'), env = process.env.NODE_ENV || 'development'; var forceSsl = function (req, res, next) { if (req.headers['x-forwarded-proto'] !== 'https') { return res.redirect(['https://', req.get('Host'), req.url].join('')); } return next(); }; app.configure(function () { if (env === 'production') { app.use(forceSsl); } // other configurations etc for express go here... }
注意SailsJS(0.10.x)用户。 您可以简单地在api / policies中创build一个策略(enforceSsl.js):
module.exports = function (req, res, next) { 'use strict'; if ((req.headers['x-forwarded-proto'] !== 'https') && (process.env.NODE_ENV === 'production')) { return res.redirect([ 'https://', req.get('Host'), req.url ].join('')); } else { next(); } };
然后从config / policies.js中引用任何其他策略,例如:
'*':['authenticated','enforceSsl']
我写了一个小型节点模块,在快速项目上强制使用SSL。 它既可以在标准情况下工作,也可以在反向代理(Heroku,nodejitsu等)
被接受的答案有一个硬编码的域,如果你在几个域上有相同的代码(例如:dev-yourapp.com,test-yourapp.com,yourapp.com),那么这个域就不太好。
用这个代替:
/* Redirect http to https */ app.get('*', function(req,res,next) { if(req.headers['x-forwarded-proto'] != 'https' && process.env.NODE_ENV === 'production') res.redirect('https://'+req.hostname+req.url) else next() /* Continue to other routes if we're not redirecting */ });
https://blog.mako.ai/2016/03/30/redirect-http-to-https-on-heroku-and-node-generally/
如果你想在本地主机上testingx-forwarded-proto
头文件,你可以使用nginx来设置一个虚拟主机文件来代理你的节点应用程序的所有请求。 您的nginx vhostconfiguration文件可能如下所示
Nginx的
server { listen 80; listen 443; server_name dummy.com; ssl on; ssl_certificate /absolute/path/to/public.pem; ssl_certificate_key /absolute/path/to/private.pem; access_log /var/log/nginx/dummy-access.log; error_log /var/log/nginx/dummy-error.log debug; # node location / { proxy_pass http://127.0.0.1:3000/; proxy_set_header Host $http_host; proxy_set_header X-Real-IP $remote_addr; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; proxy_set_header X-Forwarded-Proto $scheme; } }
这里的重要部分是你正在代理所有的请求到本地端口3000(这是你的节点应用程序正在运行的地方),你正在设置一堆头,包括X-Forwarded-Proto
然后在你的应用程序像往常一样检测该头
performance
var app = express() .use(function (req, res, next) { if (req.header('x-forwarded-proto') == 'http') { res.redirect(301, 'https://' + 'dummy.com' + req.url) return } next() })
兴亚
var app = koa() app.use(function* (next) { if (this.request.headers['x-forwarded-proto'] == 'http') { this.response.redirect('https://' + 'dummy.com' + this.request.url) return } yield next })
主机
最后,你必须将这一行添加到你的hosts
文件
127.0.0.1 dummy.com
如果您将cloudflare.com作为CDN与heroku结合使用,则可以轻松地在Cloudflare中启用自动sslredirect,如下所示:
-
login并转到您的仪表板
-
select页面规则
- 添加您的域名,例如www.example.com,并切换始终使用https到
你应该看看heroku-ssl-redirect 。 它就像一个魅力!
var sslRedirect = require('heroku-ssl-redirect'); var express = require('express'); var app = express(); // enable ssl redirect app.use(sslRedirect()); app.get('/', function(req, res){ res.send('hello world'); }); app.listen(3000);
正如Derek指出的那样,在Heroku中检查X-Forwarded-Proto头文件的协议工作正常。 对于什么是值得的, 这里是我使用的Express中间件的一个要点和相应的testing。
环回用户可以使用arcseldon答案的稍微改编版本作为中间件:
服务器/中间件/ forcessl.js
module.exports = function() { return function forceSSL(req, res, next) { var FORCE_HTTPS = process.env.FORCE_HTTPS || false; if (req.headers['x-forwarded-proto'] !== 'https' && FORCE_HTTPS) { return res.redirect(['https://', req.get('Host'), req.url].join('')); } next(); }; };
服务器/ server.js
var forceSSL = require('./middleware/forcessl.js'); app.use(forceSSL());
app.all('*',function(req,res,next){ if(req.headers['x-forwarded-proto']!='https') { res.redirect(`https://${req.get('host')}`+req.url); } else { next(); /* Continue to other routes if we're not redirecting */ } });
更具体的方式来做到这一点。
app.enable('trust proxy'); app.use('*', (req, res, next) => { if (req.secure) { return next(); } res.redirect(`https://${req.hostname}${req.url}`); });