htaccess重定向到https:// www


309

我有以下htaccess代码:

<IfModule mod_rewrite.c>

RewriteEngine On
RewriteCond !{HTTPS} off
RewriteRule ^(.*)$ https://www.%{HTTP_HOST}%{REQUEST_URI} [L,R=301]
RewriteCond %{HTTP_HOST} !^www\.
RewriteRule ^(.*)$ https://www.%{HTTP_HOST}%{REQUEST_URI} [L,R=301]

</IfModule>

我希望https://www.使用HTTPS 将我的站点重定向到该站点,并强制执行该www.子域,但是当我访问http://www.(不使用HTTPS)时,它不会将我重定向到https://www使用HTTPS。


应该是RewriteCond %{HTTPS} =off
Michael Berkowski

1
如果我这样做,它将重定向到https:// wwwwww。
bigben

亲爱的@bigben您在这里接受了错误的答案!您可以在我的答案中找出其错误原因。
阿米尔·佛

Answers:


632

要首先强制使用HTTPS,您必须检查正确的环境变量%{HTTPS} off,但是上面的规则会加上前缀。www.由于您有第二条要执行的规则www.,请勿在第一条规则中使用它。

RewriteEngine On
RewriteCond %{HTTPS} off
# First rewrite to HTTPS:
# Don't put www. here. If it is already there it will be included, if not
# the subsequent rule will catch it.
RewriteRule .* https://%{HTTP_HOST}%{REQUEST_URI} [L,R=301]
# Now, rewrite any request to the wrong domain to use www.
# [NC] is a case-insensitive match
RewriteCond %{HTTP_HOST} !^www\. [NC]
RewriteRule .* https://www.%{HTTP_HOST}%{REQUEST_URI} [L,R=301]

关于代理

在某些形式的代理之后(客户端通过HTTPS连接到代理,负载均衡器,Passenger应用程序等),该%{HTTPS}变量可能永远不会存在on并导致重写循环。这是因为即使客户端和代理/负载平衡器正在使用HTTPS,您的应用程序实际上仍在接收纯HTTP通信。在这种情况下,请检查X-Forwarded-Proto标题而不是%{HTTPS}变量。该答案显示了适当的过程


14
在某些情况下,您的证书可能仅对单个域有效(例如,它可以与www一起使用,但不能与www一起使用)。在这种情况下,请先重定向到正确的域,然后再重定向到https,否则您将在浏览器中收到证书错误消息。
尼克·本森

19
当我使用RewriteRule ^(.*)$ https://%{HTTP_HOST}%{REQUEST_URI} [L,R=301]exaple.com/?bla=%20之类的URL 成为exaple.com/?bla=%2520时,即百分号已被编码。考虑使用该标志NE来防止双重编码:RewriteRule .* https://%{HTTP_HOST}%{REQUEST_URI} [NE,L,R=301]
击败

5
这给了我一台服务器上的重定向循环,而另一台服务器上可以工作。我真的不知道为什么
user151496 '16

4
@ user151496发生故障的服务器是否使用任何类型的HTTP代理,例如通过Varnish缓存传递或传递到Passenger?如果是这样,您可能必须检查X-Forwarded-Proto标题以验证HTTPS而不是%{HTTPS}变量。您没有说是导致循环的www部分,还是HTTPS部分,但这是我想到的第一件事。
Michael Berkowski

5
严格来说,您上面的两个规则的顺序错误。如果有请求http://example.com(例如HTTP和非www),那么您将获得双重重定向。首先到https://example.com(第一条规则),然后再到https://www.example.com(第二条规则)。您可以通过简单地反转这两个规则来解决此问题,因为这两个规则都将重定向到HTTPS。
怀特先生

148

Michals的答案对我有用,尽管做了一些小的修改:

问题:

如果您具有单个站点安全证书,则该浏览器将尝试在不使用https:// www的情况下访问您的页面。(或您的证书覆盖的任何域)收到重定向到安全正确的https页面之前,都会显示一个难看的红色警告屏幕。

首先使用重定向到www(或证书所覆盖的任何域),然后再执行https重定向。这将确保您的用户不会遇到任何错误,因为您的浏览器看到的证书不包含当前网址。

#First rewrite any request to the wrong domain to use the correct one (here www.)
RewriteCond %{HTTP_HOST} !^www\.
RewriteRule ^(.*)$ https://www.%{HTTP_HOST}%{REQUEST_URI} [L,R=301]

#Now, rewrite to HTTPS:
RewriteCond %{HTTPS} off
RewriteRule ^(.*)$ https://%{HTTP_HOST}%{REQUEST_URI} [L,R=301]

5
+1,因为它是这种情况下的更好选择,但是请注意,这不会阻止客户端访问时发生相同的问题https://example.com,但我认为这是用户输入的可能性最小的格式。(接受的答案也会有相同的问题)
Joshua Goossen

@Larzan:那就错了。仅因为您执行了2次真正的重定向,才发生证书异常。将“ [L,R = 301]”替换为“ [R = 301]”。这样,规则就不会中止。L = LAST
defim 2016年

如果您只需要在上https://没有www证书就可以处理www,只需将此规则添加到解决方案中即可:RewriteCond %{HTTP_HOST} !^www\. RewriteCond %{HTTPS} on RewriteRule ^(.*)$ http://www.%{HTTP_HOST}%{REQUEST_URI}[L,R=301] 它只是http尝试连接时返回https://example.com以避免证书错误。
埃里克·伯瑞尔

1
无论如何,都应该颠倒这两个规则(如您所做的那样),以防止在请求时出现双重重定向http://example.com(即HTTP而没有www)
MrWhite

@EricBurel在这种情况下,您无法避免cert错误-SSL握手发生在代码执行之前(首先是SSL的全部内容)。如果您的重定向能够在浏览器证书错误之前执行则表明该请求已经通过不安全的连接发出-这将是SSL模型的根本失败。
怀特先生

99

如果您使用的是CloudFlare或类似的CDN,则此处提供的%{HTTPS}解决方案将导致无限循环错误。如果您是CloudFlare用户,则需要使用以下命令:

RewriteEngine On
RewriteCond %{HTTP:X-Forwarded-Proto} =http
RewriteRule ^ https://%{HTTP_HOST}%{REQUEST_URI} [L,R=301]

2
请注意,在CloudFlare的支持网站目前的建议是略有不同:support.cloudflare.com/hc/en-us/articles/...
ColinMcDermott

1
同意@ h0mayun,Cloudflare的建议会在重定向循环中提供结果,而此代码在此效果很好-谢谢!
hobailey

2
我在ec2上运行angularjs。使用RewriteCond%{HTTPS}!= on的解决方案为我提供了无限重定向(不确定原因)。使用X-Forwarded-Proto的此解决方案似乎可以解决问题。谢谢!
马克·沃特金斯

3
我修改=http!=https为我们的环境。 X-Forwarded-Proto标头未声明为http,!=https则技巧也没有声明。
Johnathan Elmore

感谢您的见解!我花了几个小时试图弄清楚为什么{HTTPS}不起作用。我尝试了{ENV:HTTPS}甚至{SERVER_PORT} 443,但是最后是因为我需要检查Cloudflare的自定义HTTP请求标头。
camslice

56

糟糕的解决方案,为什么!

永远不要使用下面的解决方案,因为当您使用他们的代码时,就像这样:

RewriteCond %{HTTPS} off
RewriteRule .* https://%{HTTP_HOST}%{REQUEST_URI} [L,R=301]

RewriteCond %{HTTP_HOST} !^www\. [NC]
RewriteRule .* https://www.example.com%{REQUEST_URI} [L,R=301]

浏览器转到:

http://example.com

然后重定向到:

https://example.com

然后重定向到:

https://www.example.com

这是太多的要求对服务器的。

甚至接受的大多数答案都存在此问题。


最佳解决方案和答案

此代码有一个[OR]条件,可以防止url双重更改!

RewriteEngine on
RewriteCond %{HTTPS} off [OR]
RewriteCond %{HTTP_HOST} !^www\. [NC]
RewriteRule (.*) https://www.example.com%{REQUEST_URI} [R=301,L]

3
“错误的解决方案和原因!” -这些规则的顺序错误。颠倒这两个规则,这将是正确的-您只会获得一个重定向,而不是两个。
怀特先生

4
是的,给定的代码会导致2次重定向-我没有争议-我只是说您只需颠倒这些规则即可解决此问题,不需要其他更改。(“接受的”答案确实是不正确的-似乎是您所指的-指令的顺序错误。)
MrWhite

1
是@AmirForsati是正确的。它重定向两次,这应该是公认的答案。
扎基尔·侯赛因'18

4
如果要保留域名变量,可以使用此选项:RewriteEngine On RewriteCond %{HTTPS} off RewriteCond %{HTTP_HOST} !^www\. [NC] RewriteRule .* https://www.%{HTTP_HOST}%{REQUEST_URI} [L,R=301] RewriteCond %{HTTPS} off RewriteRule .* https://%{HTTP_HOST}%{REQUEST_URI} [L,R=301]
I.devries'Sep

这会将我重定向到wp-content/cache/page_enhanced/,然后依此类推。我怎样才能解决这个问题?编辑:看来我需要将其放在的顶部.htaccess。感谢您的脚本:)
Giacomo

35

这是我为代理而不是代理用户找到的最佳方法

RewriteEngine On

### START WWW & HTTPS

# ensure www.
RewriteCond %{HTTP_HOST} !^www\. [NC]
RewriteRule ^ https://www.%{HTTP_HOST}%{REQUEST_URI} [L,R=301]

# ensure https
RewriteCond %{HTTP:X-Forwarded-Proto} !https
RewriteCond %{HTTPS} off
RewriteRule ^ https://%{HTTP_HOST}%{REQUEST_URI} [L,R=301]

### END WWW & HTTPS

2
正确 这是我为代理而不是代理用户 +1 找到的最佳方法
Deep 3015

1
这是最好的解决方案,因为它可以解决多个301重定向
Niraj Chauhan

1
有史以来最好的解决方案。
SM Jobayer Alam

1
好答案。这是唯一为我工作的人。如果您在Cloudflare后面,则可以使用(尽管我在Cloudflare上没有设置页面规则)。
jasonco '19

唯一适用于我所有情况的解决方案。但是,如果我想做相反的事情并删除所有“ www”,该怎么办?
FedeKrum

27

有很多解决方案。这是直接处理此问题的apache Wiki的链接。

http://wiki.apache.org/httpd/RewriteHTTPToHTTPS

RewriteEngine On
# This will enable the Rewrite capabilities

RewriteCond %{HTTPS} !=on
# This checks to make sure the connection is not already HTTPS

RewriteRule ^/?(.*) https://%{SERVER_NAME}/$1 [R,L]
# This rule will redirect users from their original location, to the same location but using HTTPS.
# i.e.  http://www.example.com/foo/ to https://www.example.com/foo/
# The leading slash is made optional so that this will work either in httpd.conf
# or .htaccess context

我发现通过改变重写条件 RewriteCond %{HTTPS} off,以RewriteCond %{HTTPS} !=on该重定向会经常发生,这似乎是更好的答案给我。
塞缪尔·霍克斯比-罗宾逊,2016年

此解决方案应被视为正确答案!也为我工作!
AndrewShmig

11

要将http://https://重定向到https:// www,您可以在所有版本的apache上使用以下规则:

RewriteEngine on

RewriteCond %{HTTPS} off [OR]
RewriteCond %{HTTP_HOST} !^www\.
RewriteRule ^ https://www.example.com%{REQUEST_URI} [NE,L,R]

阿帕奇2.4

RewriteEngine on

RewriteCond %{REQUEST_SCHEME} http [OR]
RewriteCond %{HTTP_HOST} !^www\.
RewriteRule ^ https://www.example.com%{REQUEST_URI} [NE,L,R]

请注意,自Apache 2.4起,可以使用%{REQUEST_SCHEME}变量。


1
问题!:如果HTTP_HOST已经包含www。但方案不是HTTPS,那么您最终会看到www.www。在您的主机中。
Jpsy

@Jpsy,你是对的。我已经更新了重定向目标。感谢您的输入。
starkeen

1
这几乎是我一直在寻找的,但是我想像其他示例一样保持域的通用性。可能吗?
cronoklee

8

如果您使用的是CloudFlare,请确保使用类似以下的内容。

# BEGIN SSL Redirect
<IfModule mod_rewrite.c>
RewriteEngine On
RewriteCond %{HTTP:X-Forwarded-Proto} =http
RewriteRule ^ https://%{HTTP_HOST}%{REQUEST_URI} [L,R=301]
</IfModule>
# END SSL Redirect

这将使您摆脱重定向循环,并将您的网站安全地重定向到SSL。

PS:如果检查mod_rewrite.c是个好主意!


它不会将https:// theurlwithoutwww.com重定向到https:// www。
aredthedroids

如果您事先有一些“添加www”指令,这实际上是唯一可行的解​​决方案。其他解决方案给了我“许多重定向”。
Daniel.P。


2
RewriteEngine On
RewriteCond %{HTTP_HOST} !^www.
RewriteRule ^(.*)$ https://www.%{HTTP_HOST}/$1 [R=301,L]

注意:确保已完成以下步骤

  1. sudo a2enmod重写
  2. sudo服务apache2重新启动
  3. 在/etc/apache2/sites-available/000-default.conf中的vhost文件中添加“跟随”
<Directory /var/www/html>
  Options Indexes FollowSymLinks MultiViews
  AllowOverride All
  Order allow,deny
  allow from all
  Require all granted
</Directory>

现在,您的.htaccess将可以使用,并且您的站点将重定向到http://到https:// www



0

在您的.htaccess文件中设置

RewriteEngine On
RewriteCond %{HTTP_HOST} !^www.
RewriteRule ^(.*)$ https://www.%{HTTP_HOST}/$1 [R=301,L]
RewriteCond %{HTTPS} !=on
RewriteRule ^ https://%{HTTP_HOST}%{REQUEST_URI} [L,R=301]


-2

我尝试第一个答案,它不起作用...这项工作:

<IfModule mod_rewrite.c>
RewriteEngine On
RewriteBase /

RewriteCond %{ENV:HTTPS} !=on
RewriteRule ^.*$ https://%{SERVER_NAME}%{REQUEST_URI} [R,L]

# BEGIN WordPress
<IfModule mod_rewrite.c>
RewriteEngine On
RewriteBase /
RewriteRule ^index\.php$ - [L]
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule . /index.php [L]
</IfModule>

# END WordPress
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.