【问题标题】:How can I prevent ProxyPreserveHost from redirecting indefinitely?如何防止 ProxyPreserveHost 无限期重定向?
【发布时间】:2021-03-15 08:25:06
【问题描述】:

我正在尝试拥有两个子域,my.domain.com 和 foo.my.domain.com,它们都重定向到我的 Apache2 服务器 (127.0.0.1/my/) 的同一目录。

但是,我希望那里的脚本能够分辨出请求来自哪个域。在我看来,有两种方法可以做到这一点:

  • 使用 RewriteRule 在每个包含 .php 的请求末尾添加 ?foo=bar,但这听起来很脏
  • 使用 ProxyPreserveHost 向 PHP 脚本指示原始域是什么,这听起来更正常和理智。

但是,当我启用 ProxyPreserveHost 时,我得到了一个永无止境的 301 重定向循环。 这是虚拟主机配置:

My.Domain.com:

<IfModule mod_ssl.c>
<VirtualHost *:443>
    ServerName my.domain.com

    ProxyPass / http://127.0.0.1/my/
    ProxyPassReverse / http://127.0.0.1/my/
    ProxyRequests Off

    SSLCertificateFile /etc/letsencrypt/live/my.domain.com/fullchain.pem
    SSLCertificateKeyFile /etc/letsencrypt/live/my.domain.com/privkey.pem
    Include /etc/letsencrypt/options-ssl-apache.conf
</VirtualHost>
</IfModule>

Foo.My.Domain.Com:

<IfModule mod_ssl.c>
<VirtualHost *:443>
    ServerName foo.my.domain.com

    ProxyPass / http://127.0.0.1/my/
    ProxyPassReverse / http://127.0.0.1/my/
    ProxyRequests Off
    ProxyPreserveHost On      # creates 301 loop!

    SSLCertificateFile /etc/letsencrypt/live/my.domain.com/fullchain.pem
    SSLCertificateKeyFile /etc/letsencrypt/live/my.domain.com/privkey.pem
    Include /etc/letsencrypt/options-ssl-apache.conf
</VirtualHost>
</IfModule>

注意:我也尝试将ProxyPassReverse / https://foo.my.domain.com/ 放在第二个域foo.domain.com 中,但没有任何改变。

如何在不引起重定向循环的情况下保留主机?

【问题讨论】:

    标签: php redirect mod-rewrite apache2 reverse-proxy


    【解决方案1】:

    正如文档所述,设置 ProxyPreserveHost 会导致 apache 忽略 ProxyPass 指令并使用提供的主机名,因此您尝试将请求转发到 foo.my.domain.com 导致无限重定向循环。我认为我不会将我的服务器设置为代理转发到本地主机,但鉴于您已经拥有,我可以建议的最简单的更改是摆脱 ProxyPreserveHost 语句并将 ProxyPass 更改为http://127.0.0.1/myfoo 之类的东西,并且添加一些代码来保留 foo 地址。

    【讨论】:

    • 我将如何以及在哪里添加那段代码?一旦我被重定向,我在 PHP 端看不到任何可以让我知道地址的东西:
    • 我不确定你是如何映射 apache 的,但是你会有一个 web 头目录,它可能有一个子目录“my”,并且可能有一个 index.php 那里 - 或者可能是你的配置将其映射到不同的脚本。在任何一种情况下,您都希望 myfoo 转到另一个脚本,该脚本设置您通过 myfoo 进入的一些全局变量或其他指示符,然后调用另一个脚本。还有很多其他的方式来说明这一点——这只是一个例子。如果我重新开始,我将完全失去内部代理并将其设置为标准网站。
    • 所以您确认在 Apache 下没有办法让两个地址重定向到同一个网站,同时仍然让该网站知道来自哪个地址的请求?而且我将不得不复制整个网站或使用链接目录来完成这些工作?
    【解决方案2】:

    如果你想在 php 脚本中获取域名,有更好的解决方案:

    在 php 中:

    echo $_SERVER['SERVER_NAME'];
    echo $_SERVER['HTTP_HOST'];
    

    并在应用程序虚拟主机中:

    UseCanonicalName off
    

    这里建议:

    https://stackoverflow.com/a/50301646/9287628

    更新

    将此添加到您的 appache 虚拟主机:

    RequestHeader set mydomain "my.domain.com"
    

    还有一个:

    RequestHeader set mydomain "foo.my.domain.com"
    

    然后像这样在 php 中检索它:

    echo $_REQUEST["mydomain"];
    

    如果它没有识别到​​ RequestHeader:

    a2enmod headers
    systemctl restart apache2.service // or whatever your appache service name is httpd 
    

    RockOver 找到了解决方案

    $_SERVER["HTTP_X_FORWARDED_HOST"];
    

    将反映实际的域名,并将在重定向期间保留。

    【讨论】:

    • UseCanonicalName 设置为 Off,var_dump($_SERVER['SERVER_NAME']) 仍返回 127.0.0.1
    • in 检查元素 -> 网络 ->(第一个请求)-> 标头选项卡 -> 请求标头:您在“主机”键中看到什么?
    • 在请求标头中,“主机”键,DNS 名称出现。 foo.my.domain.com
    • HTTP_HOST 和 SERVER_NAME 都返回 127.0.0.1
    • 它没有用。很抱歉,我找到了自己的解决方案,我需要的是 $_SERVER["HTTP_X_FORWARDED_HOST"]。
    【解决方案3】:

    找到了:

    $_SERVER["HTTP_X_FORWARDED_HOST"] 包含主机名,因此在我的情况下为 foo.my.domain.com。我最终不需要UseCanonicalName 也不需要ProxyPreserveHost。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2012-07-21
      • 1970-01-01
      • 2012-06-24
      • 2016-10-06
      • 2019-02-26
      • 1970-01-01
      • 2021-03-09
      • 2017-11-08
      相关资源
      最近更新 更多