如何根据请求头的值使nginx进行重定向?

45
我正在使用Cloudflare代理托管一个网站,这意味着我的服务器所有请求都通过端口80进行,即使Cloudflare处理HTTP(端口80)和HTTPS(端口443)流量。
为了区分两者,Cloudflare会包含一个名为“X-Forwarded-Proto”的头部信息,该信息基于用户连接设置为“http”或“https”。
我想将每个具有“X-Forwarded-Proto: http”头部信息的请求重定向到我的网站的SSL版本。如何使用nginx配置实现此操作?

请注意,CloudFlare不托管您网站的内容。注:PageRules在这里也可能适用,因为您似乎只是想将http://转发到https://。有关PageRules的信息,请参见:https://support.cloudflare.com/hc/en-us/articles/200168306-Is-there-a-tutorial-for-Page-Rules-。 - damoncloudflare
2个回答

62

最简单的方法是使用if指令。如果有更好的方法,请告诉我,因为有人说if指令效率低下。 Nginx会将横线转换为头部下划线,因此X-Forwarded-Proto变成了$http_x_forwarded_proto

server {
    listen 80;
    server_name example.com; # Replace this with your own hostname
    if ($http_x_forwarded_proto = "http") {
        return 301 https://example.com$request_uri;
    }

    # Rest of configuration goes here... 
}

4
不确定你和谁交流,但如果不是低效的话,当被滥用于重写领域之外的目的时,它容易出错。请仔细阅读《if语句的邪恶》一文,以了解其缺点。你的解决方案正是它设计的目的,所以应该可以正常工作。 - user1600649
13
只是一个小提示:如果您有多个server_name值,最好将返回字符串替换为更通用的版本:return 301 https://$host$request_uri; - Alekc
1
兄弟,如果nginx中有“if”语句的话是很邪恶的;)“if”会生成许多实例,导致nginx变慢并且需要更多的内存。 - user989840
2
如果在这种情况下if语句并不邪恶:“在位置上下文中唯一可以安全执行的操作是:返回和重写”。https://www.nginx.com/resources/wiki/start/topics/depth/ifisevil/ - Matthias Baumgart

10

尝试使用map指令:http://nginx.org/en/docs/http/ngx_http_map_module.html#map

类似这样的东西...

map $http_x_forwarded_proto     $php_backend {
    "https"          "https_php_backend named loc";
    default        "default_php_backend named loc";
}
server{
    location / {
         proxy_pass http://$php_backend;
    }
}

这段代码比较抽象,但你可以尝试这种方法...


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接