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

发布于 2024-09-26 09:24:48 字数 52 浏览 3 评论 0原文

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

Is there a way to redirect HTTPS requests to HTTP by adding a rule in the domain's vhost file?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(8

情深已缘浅 2024-10-03 09:24:48

为什么这样的东西有用?乍一看,我不确定是否可以做到。但这提出了一个有趣的问题。

您可以尝试在配置文件中添加重定向语句并重新启动服务器。可能会发生两种可能性:

  1. 服务器将发出重定向 - 您似乎想要的。
  2. 服务器将首先进行 https 交换,然后发出重定向,在这种情况下,有什么意义呢?

如果我想出更具体的东西,我会添加更多内容。

更新: (几个小时后)
你可以试试这个。您需要将其放入 nginx.conf 文件中 -

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

向客户端发送永久重定向。我假设您使用 https 端口 443(默认)。

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

添加此项,以便您在端口 80 上的正常 http 请求不会受到干扰。

更新: 2016 年 12 月 18 日
- 在 nginx 版本 > 中应使用 server_name _ 代替 server_name _ * 0.6.25(感谢@Luca Steeb)

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?

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 -

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.

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

Add this so that your normal http requests on port 80 are undisturbed.

UPDATE: 18th Dec 2016
- server_name _ should be used instead of server_name _ * in nginx versions > 0.6.25 (thanks to @Luca Steeb)

深者入戏 2024-10-03 09:24:48

Nginx 应避免使用 rewriteif。著名的一句话是,“Nginx 不是 Apache”:换句话说,Nginx 有比重写更好的方法来处理 URL。从技术上讲,return 仍然是重写模块的一部分,但它不承担 rewrite 的开销,并且不像 if 那样充满警告。代码>.

Nginx 有一个完整的页面来解释 为什么 if 是“邪恶的”。它还提供了一个建设性的页面,解释为什么rewriteif是不好,以及如何解决它。以下是该页面关于 rewriteif 的内容:

这是一种错误、麻烦且无效的方式。

您可以使用 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;
}

如果您预计很多机器人不会发送 Host 标头,您可以使用 $host 而不是 $http_host,只要您坚持使用端口 80 和 443。否则,您需要动态填充 $http_host 替代品。尽管使用了 if,但只要该代码出现在 server 的根目录中(而不是在 location 块中),它就是高效且安全的。但是,您需要使用默认服务器才能适用,而使用 https 时应避免这种情况。

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

如果您想对特定路径强制实施 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;
    }
}

如果您的服务器未与客户端直接通信(例如,如果您使用的是 CloudFlare),那么事情会变得更加复杂。您需要确保与客户端直接通信的任何服务器都会向请求添加适当的 X-Forwarded-Proto 标头。

使用这个是一个混乱的提议;有关完整说明,请参阅 IfIsEvil。为了使其有用,出于各种复杂的原因,if 块不能位于 location 块内。这强制使用 rewrite 进行 URI 测试。 简而言之,如果您必须在生产服务器上使用它……不要这样做。可以这样想:如果您已经无法满足 Apache 的需求,那么您就已经无法满足此解决方案的需求。

/secure、/secure/ 以及 /secure/ 中的任何内容都将强制执行 https,而所有其他 URI 将强制执行 http。 (?! ) PCRE 构造是一个否定先行断言(?: ) 是一个非捕获组

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;
    }
}

rewrite and if should be avoided with Nginx. The famous line is, "Nginx is not Apache": in other words, Nginx has better ways to handle URLs than rewriting. 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.

Nginx has an entire page on why if is "evil". It also provides a constructive page explaining why rewrite and if are bad, and how you can work around it. Here's what the page has to say regarding rewrite and if:

This is a wrong, cumbersome, and ineffective way.

You can solve this problem properly using 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. 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. However, you'd need to be using a default server for this to be applicable, which should be avoided with 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:

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. You'll need to ensure that any server in direct communication with the client adds an appropriate X-Forwarded-Proto header to the request.

Using this is a messy proposition; for a full explanation, see IfIsEvil. In order for this to be useful, the if block cannot be inside a location block, for a variety of complex reasons. This forces the use of rewrite for URI testing. 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.

/secure, /secure/, and anything in /secure/ will enforce https, while all other URIs will enforce http. The (?! ) PCRE construct is a negative lookahead assertion. (?: ) 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;
    }
}
没企图 2024-10-03 09:24:48
location / {
    if ($scheme = https) {
        rewrite ^(.*)? http://$http_host$1 permanent;
    }
}
location / {
    if ($scheme = https) {
        rewrite ^(.*)? http://$http_host$1 permanent;
    }
}
怎会甘心 2024-10-03 09:24:48

这个问题更适合 serverfault.com 网站。

重定向到 http 的更好方法:

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

这避免了重写中的“if”子句和正则表达式,这是迄今为止其他解决方案的功能。两者都会对性能产生影响,但实际上,您必须拥有相当多的流量才能发挥作用。

根据您的设置,您可能还想在listen 子句中指定一个ip,并且可能在上面指定一个servername 子句。按原样,它将适用于所有域名的所有端口 443 请求。您通常希望每个域都有一个带 https 的 IP,因此将上述内容与 IP 绑定比将其与域名绑定更切中要害,但也有一些变化,例如,所有域都是一个域的子域。

编辑:TLS 现在已经接近通用,并且有了服务器名称识别 (SNI),它允许多个域上的 HTTPS 站点共享单个 IP。 这里有一篇很好的文章

this question would have been better suited to the serverfault.com site.

A better way to do the redirect to 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. 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. As is, it will apply to all port 443 requests for all domain names. 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.

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. There's a good write-up here

烂柯人 2024-10-03 09:24:48

这帮助了我:

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

This helped me:

server {
    listen 443;
    server_name server.org www.server.org;
    rewrite ^ http://$server_name$request_uri? permanent;
}
若沐 2024-10-03 09:24:48

打开您的域的 Nginx 配置文件。该文件通常位于 Linux 系统上的 /etc/nginx/sites-available/ 目录中。
比在 HTTPS(SSL) 配置的服务器块内添加以下行来执行重定向:

    server {
    listen 443 ssl;
    server_name your-domain.com;
    ssl_certificate /path/to/your/ssl/certificate.crt;
    ssl_certificate_key /path/to/your/ssl/private-key.key;

    # Perform the HTTPS to HTTP redirect
    location / {
        return 301 http://$host$request_uri;
    }

    # Additional SSL configuration settings go here
    }

保存并退出文本编辑器,然后使用以下命令测试您的 nginx 配置:

sudo nginx -t

if temrinal 显示“ok” " 和 "valid" 那么你可以使用以下命令重新加载 nginx 配置:

sudo systemctl reload nginx

此配置将使用 301(永久)重定向将所有 HTTPS 请求重定向到 HTTP

Open the Nginx configuration file for your domain. This file is typically located in the /etc/nginx/sites-available/ directory on Linux systems.
than inside your server block for the HTTPS(SSL) configuration, add the folowing lines to perform the redirection:

    server {
    listen 443 ssl;
    server_name your-domain.com;
    ssl_certificate /path/to/your/ssl/certificate.crt;
    ssl_certificate_key /path/to/your/ssl/private-key.key;

    # Perform the HTTPS to HTTP redirect
    location / {
        return 301 http://$host$request_uri;
    }

    # Additional SSL configuration settings go here
    }

save and exit text editor than test your nginx config with :

sudo nginx -t

if temrinal showed "ok" and "valid" then you can reload nginx config using :

sudo systemctl reload nginx

This configuration will redirect all HTTPS requests to HTTP with a 301 (permanent) redirect

夏有森光若流苏 2024-10-03 09:24:48

唯一简单的规则已经在我上面的帖子中解释过:

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

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;
}
梦醒时光 2024-10-03 09:24:48
server{
  listen 80;
  listen [::]:80;

  server_name mywebsite.com ;
  return 301 https://$host$request_uri;
}

插入此代码后,HTTP 默认服务器的所有流量都会重定向到 HTTPS。

server{
  listen 80;
  listen [::]:80;

  server_name mywebsite.com ;
  return 301 https://$host$request_uri;
}

After inserting this code, all traffic for the HTTP default server redirects to HTTPS.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文