【发布时间】:2011-04-23 01:43:07
【问题描述】:
有没有办法通过在域的 vhost 文件中添加规则来将 HTTPS 请求重定向到 HTTP?
【问题讨论】:
有没有办法通过在域的 vhost 文件中添加规则来将 HTTPS 请求重定向到 HTTP?
【问题讨论】:
为什么这样的东西有用?乍一看,我不确定它是否可以完成。但它提出了一个有趣的问题。
您可以尝试在配置文件中添加重定向语句并重新启动服务器。可能会发生两种可能性:
如果我想出更具体的内容,会添加更多内容。
更新: (几个小时后) 你可以试试这个。你需要把它放在你的 nginx.conf 文件中 -
server {
listen 443;
server_name _ *;
rewrite ^(.*) http://$host$1 permanent;
}
向客户端发送永久重定向。我假设您使用端口 443(默认)作为 https。
server {
listen 80;
server_name _ *;
...
}
添加此项,以便您在端口 80 上的正常 http 请求不受干扰。
更新: 2016 年 12 月 18 日
- 在 nginx 版本 > 0.6.25 中应使用 server_name _ 而不是 server_name _ *(感谢 @Luca Steeb)
【讨论】:
OpenSSL: error:140770FC:SSL routines:SSL23_GET_SERVER_HELLO:unknown protocol Unable to establish SSL connection.
ssl on 的情况下将 443 重定向到 80,与 https 不匹配,它不应该工作。但是如果添加ssl on,则需要ssl_certificates,并且必须提供正确的证书。所以我认为它不能在没有证书的情况下将 https 重定向到 http。相关问题:stackoverflow.com/questions/3470290/…
server_name _ 应该在 nginx 版本 > 0.6.25 中使用而不是 server_name _ *
rewrite 和 if 应避免使用 Nginx。著名的一句话是,“Nginx 不是 Apache”:换句话说,Nginx 处理 URL 的方法比重写更好。 return 在技术上仍然是重写模块的一部分,但它没有 rewrite 的开销,并且不像 if 那样需要注意。
Nginx 在why if is "evil" 上有一个完整的页面。它还提供了一个建设性的页面来解释why rewrite and if are bad,以及如何解决它。以下是该页面关于rewrite 和if 的内容:
这是一种错误、繁琐且无效的方式。
您可以使用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 构造是negative lookahead assertion。 (?: ) 是 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;
}
}
【讨论】:
这个问题更适合 serverfault.com 网站。
重定向到 http 的更好方法:
server {
listen 443;
return 301 http://$host$request_uri;
}
这避免了重写中的“if”子句和正则表达式,它们是迄今为止其他解决方案的特征。两者都对性能有影响,但在实践中,您必须拥有相当多的流量才有意义。
根据您的设置,您可能还想在 listen 子句中指定一个 ip,或许还需要在上面的 servername 子句中指定一个。照原样,它将适用于所有域名的所有端口 443 请求。您通常希望每个域都有一个带有 https 的 IP,因此大多数情况下将上述内容与 IP 绑定比将其与域名绑定更重要,但也有一些变化,例如所有域都是一个域的子域。
编辑:TLS 现在已接近通用,并且使用它的服务器名称识别 (SNI),它允许多个域上的 HTTPS 站点共享一个 IP。有一篇很好的文章here
【讨论】:
这对我有帮助:
server {
listen 443;
server_name server.org www.server.org;
rewrite ^ http://$server_name$request_uri? permanent;
}
【讨论】:
不是一个合适的解决方案,但我能够通过使用 Cloudflare 解决我的用例,它透明地为我处理 SSL。
【讨论】:
我上面的帖子已经解释了唯一简单的规则:
server {
listen ip:443;
server_name www.example.com;
rewrite ^(.*) http://$host$1 permanent;
}
【讨论】:
server{
listen 80;
listen [::]:80;
server_name mywebsite.com ;
return 301 https://$host$request_uri;
}
插入此代码后,HTTP 默认服务器的所有流量都会重定向到 HTTPS。
【讨论】: