【问题标题】:.htaccess fails to rewrite when url contains HTTPS当 url 包含 HTTPS 时,.htaccess 无法重写
【发布时间】:2020-11-29 23:56:15
【问题描述】:

我已经坐了很长时间了,无法理解它。

基本上,我最终要寻找的功能类似于以下内容:

http://example.com 重定向到 https://example.com - 当前工作

为了

http://*.example.comhttps://*.example.com 重定向到 https://example.com/* - 不起作用。目前,所有子域都被重定向到主域,没有它们各自的文件夹路径。此外,当转到https://test.example.com 时,它根本不会重定向。

这是来自sites-enabledexample.com.conf

<IfModule mod_ssl.c>

    <VirtualHost *:80>
        ServerName example.com
        ServerAlias www.example.com
#       Redirect permanent / https://example.com/

        <Directory /var/www/example.com/public_html>
            Options FollowSymLinks
            AllowOverride All
            Require all granted
        </Directory>
        
        <IfModule mod_rewrite.c>
            # Redirect all traffic to HTTPS
            RewriteCond %{HTTPS} !on
            RewriteRule ^(.*)$ https://%{HTTP_HOST}%{REQUEST_URI} [QSA,R=301,L]
        </IfModule>


    </VirtualHost>

    <VirtualHost _default_:443>
        ServerAdmin webmaster@localhost
        ServerName example.com
        ServerAlias www.example.com
        DocumentRoot /var/www/example.com/public_html

        <Directory /var/www/example.com/public_html>
            Options FollowSymLinks
            AllowOverride All
            Require all granted
        </Directory>

        <IfModule mod_rewrite.c>
            # Remove www
            RewriteCond %{HTTP_HOST} ^www\.(.+)$ [NC]
            RewriteRule ^(.*)$ http://%1%{REQUEST_URI} [QSA,R=301,L]

            RewriteCond %{HTTP_HOST} !^(www)\. [NC]
            RewriteCond %{HTTP_HOST} ^(.*)\.example\.com [NC]
            RewriteRule ^(.*)$ https://example.com/%1/$1 [R=301,L]
        </IfModule>

        ErrorLog ${APACHE_LOG_DIR}/error.log
        CustomLog ${APACHE_LOG_DIR}/access.log combined

        SSLEngine on
        SSLCertificateFile  /etc/ssl/civrpssl/example.com.crt
        SSLCertificateKeyFile /etc/ssl/civrpssl/example.com.key
        SSLCACertificateFile /etc/ssl/civrpssl/ca-example.com.crt

        <FilesMatch "\.(cgi|shtml|phtml|php)$">
                SSLOptions +StdEnvVars
        </FilesMatch>
        <Directory /usr/lib/cgi-bin>
                SSLOptions +StdEnvVars
        </Directory>

    </VirtualHost>
</IfModule>

最后,这是来自example.com/public_html/.htaccess

removed, see edit #2.

我希望这是一个我没有看到的相当明显的问题。否则,请有人告诉我我应该从哪里开始寻找问题?我假设 HTTPS 重定向会干扰 .htaccess 文件中的子域重定向,但我不知道我该如何改变它。

编辑 #1: 我刚刚注意到 www.example.com 抛出错误“找不到 URL”,而不是重定向到 https://example.com.htaccess第一次重写怎么没抓到?

编辑 #2:

  • 将重写从 .htaccess 移至 example.com.conf(代码已在帖子中更新)。
  • 为端口 80 添加了 VHost,本质上只是将所有流量重定向到 HTTPS。我发现重定向有效,但是它不会在重定向中包含子域,所以http://test.example.com 只会导致https://example.com
  • a2enmod rewrite,因为显然它没有启用。

【问题讨论】:

  • 80 端口的 vHost 怎么样?您发布的虚拟主机仅对example.com 的请求除外 - 不接受任何子域(包括www)。但是,如果这是您的配置中定义的第一个 vHost,那么它可能仍会捕获这些请求。否则,您的 .htaccess 指令看起来“正常”,除非您访问服务器配置,那么理想情况下,您应该在服务器配置中重定向 HTTP 和子域。
  • 感谢您的反馈!我已经更新了帖子。如果你有时间,请再看看。

标签: .htaccess mod-rewrite apache2


【解决方案1】:
ServerName example.com
ServerAlias www.example.com

&lt;VirtualHost&gt; 容器都不接受任何子域的请求,www 除外。如果 vHost 是服务器配置中第一个定义的 vHost,它仍可能捕获其他子域(实际上,any 主机名)。要捕获“任何”子域,您需要另一个“通配符”ServerAlias,形式为:

ServerAlias *.example.com

删除 &lt;IfModule mod_rewrite.c&gt; 包装器 - 它们不是必需的。如果 mod_rewrite 不可用,它们只会屏蔽错误。 &lt;IfModule&gt; 包装器仅应在这些指令完全可选并且配置要移植到 mod_rewrite 不可用的其他系统时使用。

更新:您还缺少 vHost 中的 RewriteEngine On 指令。除非已经在服务器配置的其他地方启用了重写引擎(不太可能),否则这些 mod_rewrite 指令将被完全跳过。

在 HTTP vHost(端口 80)中...

       # Redirect all traffic to HTTPS
       RewriteCond %{HTTPS} !on
       RewriteRule ^(.*)$ https://%{HTTP_HOST}%{REQUEST_URI} [QSA,R=301,L]

没有必要在 vHost 中检查 HTTPS 的端口 80,因为它始终是 off。如果您想直接从子域重定向到子目录,则需要将上面的内容更改为:

        # Redirect HTTP subdomains to HTTPS subdirectory (excluding www)
        RewriteCond %{HTTP_HOST} !^www\. [NC]
        RewriteCond %{HTTP_HOST} ^([^.]+)\.example\.com [NC]
        RewriteRule ^/(.*) https://example.com/%1/$1 [R=301,L]

        # Redirect HTTP to HTTPS
        RewriteRule ^/(.*) https://example.com/$1 [R=301,L]

但是,如果您打算在未来实施 HSTS,那么您需要先重定向到同一主机上的 HTTPS,然后再针对端口 443 向 vHost 中的子目录发出第二次重定向。 (使用 Redirect 指令从 HTTP 重定向到 HTTPS - 目前已被注释掉 - 尽管这需要为每个子域单独(最小)vHost,这可能是不可取的。)

^/(.*) - 请注意在RewriteRule 模式 中的捕获子模式之外添加斜杠前缀。在 virtualhost 上下文中,完整的 URL 路径由 RewriteRule pattern 匹配。尾随 $ 不是必需的,因为正则表达式默认是贪婪的。

还要注意正则表达式 ([^.]+)(而不是 (.*)),它仅专门匹配子域(无点)。

在您的 HTTPS 虚拟主机(端口 443)中,您有:

       # Remove www
       RewriteCond %{HTTP_HOST} ^www\.(.+)$ [NC]
       RewriteRule ^(.*)$ http://%1%{REQUEST_URI} [QSA,R=301,L]

您正在重定向回 HTTP(尽管这似乎是您在编辑后引入的错误?)。

如果您使用REQUEST_URI 变量,则无需捕获RewriteRule 模式

然后同样的编辑适用于子域到子目录的重定向,如上所述。

总结

综合以上几点,我们有类似的东西:

<VirtualHost *:80>
    ServerName example.com
    ServerAlias www.example.com
    ServerAlias *.example.com

    #Redirect permanent / https://example.com/

    RewriteEngine On
    
    # Redirect HTTP subdomains to HTTPS subdirectory (excluding www)
    RewriteCond %{HTTP_HOST} !^www\. [NC]
    RewriteCond %{HTTP_HOST} ^([^.]+)\.example\.com [NC]
    RewriteRule ^/(.*) https://example.com/%1/$1 [R=301,L]

    # Redirect HTTP to HTTPS (www and domain apex)
    RewriteRule ^/(.*) https://example.com/$1 [R=301,L]
</VirtualHost>

<VirtualHost *:443>
    ServerAdmin webmaster@localhost
    ServerName example.com
    ServerAlias www.example.com
    ServerAlias *.example.com
    DocumentRoot /var/www/example.com/public_html

    <Directory /var/www/example.com/public_html>
        Options FollowSymLinks
        # Set "AllowOverride None" to disable .htaccess altogether
        AllowOverride All
        Require all granted
    </Directory>

    RewriteEngine On

    # Remove www
    RewriteCond %{HTTP_HOST} ^www\.(.+)$ [NC]
    RewriteRule ^ https://%1%{REQUEST_URI} [QSA,R=301,L]

    # Redirect other subdomains to subdirectory
    RewriteCond %{HTTP_HOST} ^([^.]+)\.example\.com [NC]
    RewriteRule ^/(.*) https://example.com/%1/$1 [R=301,L]

    ErrorLog ${APACHE_LOG_DIR}/error.log
    CustomLog ${APACHE_LOG_DIR}/access.log combined

    SSLEngine on
    SSLCertificateFile  /etc/ssl/civrpssl/example.com.crt
    SSLCertificateKeyFile /etc/ssl/civrpssl/example.com.key
    SSLCACertificateFile /etc/ssl/civrpssl/ca-example.com.crt

    <FilesMatch "\.(cgi|shtml|phtml|php)$">
            SSLOptions +StdEnvVars
    </FilesMatch>
    <Directory /usr/lib/cgi-bin>
            SSLOptions +StdEnvVars
    </Directory>

</VirtualHost>

您应该首先测试 302(临时)重定向以避免潜在的缓存问题。

并在测试前清除浏览器缓存(任何错误的 301 都会被浏览器缓存)。

【讨论】:

  • 干杯伙伴!这就像一个魅力。我还注意到原始帖子和答案都缺少RewriteEngine on,所以我也添加了。
  • Redirect from HTTP to HTTPS using the Redirect directive - currently commented out. 上的后续问题。我试过这个,但假设子域在这种重定向中丢失了?是否可以通过简单地取消 Redirect 行的注释从虚拟主机中完全删除端口 80 的 Rewrite 并在 443 上处理它?
  • “我还注意到原始帖子和答案都缺少RewriteEngine on,所以我也添加了。” - 哎呀,是的,你需要那个! (除非它已经在服务器配置的其他地方启用 - 不太可能。) - 我会更新我的答案以包含它。
  • "是否可以通过简单地取消 Redirect 行的注释从虚拟主机中完全删除端口 80 的 Rewrite 并在 443 上处理它?" - 嗯,没那么简单。您需要为每个包含Redirect 的子域创建一个最小的 vHost - 所以这可能是不可取的。坚持使用 mod_rewrite,特别是如果您有许多这样的子域,可能会更好。
猜你喜欢
  • 2021-01-30
  • 1970-01-01
  • 2013-07-04
  • 1970-01-01
  • 1970-01-01
  • 2021-06-17
  • 2014-07-18
  • 2015-05-22
  • 2013-07-26
相关资源
最近更新 更多