简体   繁体   English

如何在 NGINX 上将 HTTPS 重定向到 HTTP?

[英]How do I redirect HTTPS to HTTP on NGINX?

有没有办法通过在域的 vhost 文件中添加规则来将 HTTPS 请求重定向到 HTTP?

Why is something like that useful?为什么这样的东西有用? At first look I wasn't sure if it could be done.乍一看,我不确定是否可以完成。 But it presented an interesting question.但它提出了一个有趣的问题。

You might try putting a redirect statement in your config file and restarting your server.您可以尝试在配置文件中放置重定向语句并重新启动服务器。 Two possibilities might happen:可能有两种可能:

  1. The server will issue the redirect - what you seem to want.服务器将发出重定向 - 您似乎想要什么。
  2. The server will first do the https exchange, and THEN issue the redirect, in which case, what's the point?服务器将首先进行https交换,然后发出重定向,在这种情况下,有什么意义?

Will add more if I come up with something more concrete.如果我想出更具体的东西,我会添加更多。

UPDATE: (couple of hours later) You could try this.更新:(几个小时后)你可以试试这个。 You need to put this in your nginx.conf file -你需要把它放在你的nginx.conf文件中 -

server {
       listen 443;
       server_name _ *;
       rewrite ^(.*) http://$host$1 permanent;
 }

Sends a permanent redirect to the client.向客户端发送永久重定向。 I am assuming you are using port 443 (default) for https.我假设您对 https 使用端口 443(默认)。

server {
    listen      80;
    server_name _ *;
    ...
}

Add this so that your normal http requests on port 80 are undisturbed.添加此项,以便您在端口 80 上的正常 http 请求不受干扰。

UPDATE: 18th Dec 2016 - server_name _ should be used instead of server_name _ * in nginx versions > 0.6.25 (thanks to @Luca Steeb)更新:2016年12月18日- server_name _应该用来代替server_name _ *在nginx的版本> 0.6.25(感谢@Luca Steeb)

rewrite and if should be avoided with Nginx. rewriteif应该避免使用 Nginx。 The famous line is, "Nginx is not Apache": in other words, Nginx has better ways to handle URLs than rewriting.著名的一句话是,“Nginx 不是 Apache”:换句话说,Nginx 有比重写更好的方法来处理 URL。 return is still technically part of the rewrite module, but it doesn't carry the overhead of rewrite , and isn't as caveat-ridden as if . return在技​​术上仍然是 rewrite 模块的一部分,但它不承担rewrite的开销,也不像if那样充满警告。

Nginx has an entire page on why if is "evil" . Nginx 有一整页关于为什么if是 "evil" It also provides a constructive page explaining why rewrite and if are bad , and how you can work around it.它还提供了一个建设性的页面,解释为什么要rewriteif是坏的,以及如何解决它。 Here's what the page has to say regarding rewrite and if :以下是该页面关于rewriteif

This is a wrong, cumbersome, and ineffective way.这是一种错误、繁琐且无效的方式。

You can solve this problem properly using return :您可以使用return正确解决此问题:

server {
    listen 443 ssl;

    # You will need a wildcard certificate if you want to specify multiple
    # hostnames here.
    server_name domain.example www.domain.example;

    # If you have a certificate that is shared among several servers, you
    # can move these outside the `server` block.
    ssl_certificate /path/to/cert.pem;
    ssl_certificate_key /path/to/cert.key;

    # 301          indicates a permanent redirect.  If your redirect is
    #              temporary, you can change it to 302 or omit the number
    #              altogether.
    # $http_host   is the hostname and, if applicable, port--unlike $host,
    #              which will break on non-standard ports
    # $request_uri is the raw URI requested by the client, including any
    #              querystring
    return 301 http://$http_host$request_uri;
}

If you expect a lot of bots that don't send a Host header, you can use $host instead of $http_host as long as you stick to ports 80 and 443. Otherwise, you'll need to dynamically populate an $http_host substitute.如果您期望很多机器人不发送Host标头,只要您坚持使用端口 80 和 443,您就可以使用$host而不是$http_host 。否则,您将需要动态填充$http_host替代品。 This code is efficient and safe as long as it appears in the root of server (rather than in a location block), despite using if .尽管使用if ,但只要此代码出现在server的根目录中(而不是location块中),它就是高效且安全的。 However, you'd need to be using a default server for this to be applicable, which should be avoided with https.但是,您需要使用默认服务器才能适用,这应该避免使用 https。

set $request_host $server_name:$server_port;
if ($http_host) {
    set $request_host $http_host;
}

If you want to enforce SSL/TLS for specific paths, but forbid it otherwise:如果您想对特定路径强制执行 SSL/TLS,但否则禁止:

server {
    listen 443 ssl;
    server_name domain.example;

    ssl_certificate /path/to/cert.pem;
    ssl_certificate_key /path/to/cert.key;

    location / {
        return 301 http://$host$request_uri;
    }

    location /secure/ {
        try_files $uri =404;
    }
}

server {
    listen 80;
    server_name domain.example;

    location / {
        try_files $uri =404;
    }

    location /secure/ {
        return 301 https://$http_host$request_uri;
    }
}

If your server isn't in direct communication with the client--for example, if you're using CloudFlare--things get a bit more complicated.如果你的服务器没有与客户端直接通信——例如,如果你使用 CloudFlare——事情会变得有点复杂。 You'll need to ensure that any server in direct communication with the client adds an appropriate X-Forwarded-Proto header to the request.您需要确保与客户端直接通信的任何服务器向请求添加适当的X-Forwarded-Proto标头。

Using this is a messy proposition;使用这个是一个混乱的提议; for a full explanation, see IfIsEvil .有关完整说明,请参阅IfIsEvil In order for this to be useful, the if block cannot be inside a location block, for a variety of complex reasons.为了使它有用,由于各种复杂的原因, if块不能位于location块内。 This forces the use of rewrite for URI testing.这会强制使用rewrite进行 URI 测试。 In short, if you have to use this on a production server... don't.简而言之,如果您必须在生产服务器上使用它......不要。 Think of it this way: if you've outgrown Apache, you've outgrown this solution.可以这样想:如果您已经超越了 Apache,那么您已经超越了这个解决方案。

/secure, /secure/, and anything in /secure/ will enforce https, while all other URIs will enforce http. /secure、/secure/ 和 /secure/ 中的任何内容都将强制使用 https,而所有其他 URI 将强制使用 http。 The (?! ) PCRE construct is a negative lookahead assertion . (?! ) PCRE 构造是一个否定的前瞻断言 (?: ) is a non-capturing group . (?: ) :)是一个非捕获组

server {
    # If you're using https between servers, you'll need to modify the listen
    # block and ensure that proper ssl_* statements are either present or
    # inherited.
    listen 80;
    server_name domain.example;

    if ($http_x_forwarded_proto = https) {
        rewrite ^(?!/secure)/ http://$http_host$request_uri? permanent;
    }
    if ($http_x_forwarded_proto != https) {
        rewrite ^/secure(?:/|$) https://$http_host$request_uri? permanent;
    }
}
location / {
    if ($scheme = https) {
        rewrite ^(.*)? http://$http_host$1 permanent;
    }
}

this question would have been better suited to the serverfault.com site.这个问题更适合 serverfault.com 站点。

A better way to do the redirect to http:重定向到 http 的更好方法:

server {
   listen 443;
   return 301 http://$host$request_uri;
}

This avoid both the 'if' clause and the regex in the rewrite that are features of the other solutions to date.这避免了重写中的“if”子句和正则表达式,这些都是迄今为止其他解决方案的特征。 Both have performance implications, though in practice you'd have to have quite a lot of traffic before it would matter.两者都有性能影响,但在实践中你必须有相当多的流量才重要。

Depending on your setup, you are likely to also want to specify an ip in the listen clause, and perhaps a servername clause in the above.根据您的设置,您可能还想在 listen 子句中指定一个 ip,也许还需要在上面的 servername 子句中指定。 As is, it will apply to all port 443 requests for all domain names.照原样,它将适用于所有域名的所有端口 443 请求。 You generally want an IP per domain with https, so mostly tying the above to an IP is more to the point than tying it to a domain name, but there's variations on that, eg where all domains are subdomains of one domain.您通常希望每个域都有一个带有 https 的 IP,因此将上述内容绑定到 IP 比将其绑定到域名更重要,但也有一些变化,例如所有域都是一个域的子域。

EDIT: TLS is close to universal now, and with it Server Name Identification (SNI) which allows for HTTPS sites on multiple domains sharing a single IP.编辑:TLS 现在接近于通用,并且有了它的服务器名称标识 (SNI),它允许多个域上的 HTTPS 站点共享一个 IP。 There's a good write-up here有一个很好的写了这里

This helped me:这帮助了我:

server {
    listen 443;
    server_name server.org www.server.org;
    rewrite ^ http://$server_name$request_uri? permanent;
}

不是一个合适的解决方案,但我能够通过使用 Cloudflare 解决我的用例,它透明地为我处理 SSL。

The only simple rule is already explained on the post above me:唯一的简单规则已经在我上面的帖子中解释过:

server {
    listen ip:443;
    server_name www.example.com;
    rewrite ^(.*) http://$host$1 permanent;
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM