Apache proxypass 排除规则被忽略

Apache proxypass 排除规则被忽略

我已经为这个问题苦思冥想很久了。

我有一个简单的配置,使用 Apache 的 proxypass 规则,我想在使用“catchall”规则将所有流量重定向到本地节点服务器之前提供一个排除列表。

设置如下:

ProxyPass        /contact-us !
ProxyPass        / http://localhost:3000/
ProxyPassReverse / http://localhost:3000/

上述配置的结果是/contact-us将发送到节点(localhost:3000),根据我对文档的理解,它应该被忽略。如果我为设置了目的地,/contact-us那么请求就会得到正确处理,并返回代理内容。

我是不是漏掉了什么?将 catchall( /) 添加到规则集会改变行为吗?

编辑:添加其余文件以供参考

<IfModule mod_ssl.c>
<VirtualHost *:443>
    ServerName  dev.site.com
    ServerAdmin [email protected]

    ProxyPass        /contact-us !
    ProxyPass        / http://localhost:3000/
    ProxyPassReverse / http://localhost:3000/

    DocumentRoot /var/www/site/public
    <Directory /var/www/site/public>
        Options Indexes FollowSymLinks MultiViews
        AllowOverride All
        Require all granted
    </Directory>

    <IfModule mod_headers.c>
        SetEnvIf Origin "^http(s)?://(.+\.)?(dev\.site\.com)$"  origin_is=$0

        Header always set Access-Control-Allow-Origin %{origin_is}e env=origin_is
        Header always set Access-Control-Allow-Credentials true env=origin_is
    </IfModule>

    ErrorLog ${APACHE_LOG_DIR}/dev.site.com-error.log
    CustomLog ${APACHE_LOG_DIR}/dev.site.com-access.log combined

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

答案1

我发现了我的问题并且你是对的@HBruijn。

我在虚拟主机上运行 Laravel 框架,这意味着请求被直接/index.php发送到路由,因此在第一条规则成功后(/contact-us !),请求被重写为/index.php然后在捕获所有规则中被代理。

我可以为 ( /index.php) 添加排除规则,以及以下 Fpm 请求(参见下面的日志)来解决我的问题。此解决方案可能并不适合所有人。

感谢 @yunzen 的评论,我才得以解开这一谜团 -https://serverfault.com/a/895673,通过添加LogLevel error proxy:trace5我能够看到以下内容:

[Mon Mar 04 04:39:56.876129 2019] [proxy:trace2] [pid 5564] mod_proxy.c(683): [client 220.244.99.86:51059] AH03461: attempting to match URI path '/contact-us' against prefix '/index.php' for proxying
[Mon Mar 04 04:39:56.876170 2019] [proxy:trace2] [pid 5564] mod_proxy.c(683): [client 220.244.99.86:51059] AH03461: attempting to match URI path '/contact-us' against prefix '/contact-us' for proxying
[Mon Mar 04 04:39:56.876174 2019] [proxy:trace1] [pid 5564] mod_proxy.c(736): [client 220.244.99.86:51059] AH03463: proxying is explicitly disabled for URI path '/contact-us'; declining
[Mon Mar 04 04:39:56.876880 2019] [proxy:trace2] [pid 5564] mod_proxy.c(683): [client 220.244.99.86:51059] AH03461: attempting to match URI path '/index.php' against prefix '/index.php' for proxying
[Mon Mar 04 04:39:56.876890 2019] [proxy:trace1] [pid 5564] mod_proxy.c(736): [client 220.244.99.86:51059] AH03463: proxying is explicitly disabled for URI path '/index.php'; declining
[Mon Mar 04 04:39:56.876936 2019] [proxy:trace2] [pid 5564] mod_proxy.c(683): [client 220.244.99.86:51059] AH03461: attempting to match URI path '/php72-fcgi-www/index.php' against prefix '/index.php' for proxying

请注意此单个请求引起的上下文变化。

答案2

根据 Apache(仅限 2.4.26 及更高版本)文档中的一些注释,可以使用no-proxy环境变量进行代理排除。

然而,当您需要内部重写来为您的排除页面提供服务时,情况就会变得很糟糕,因为 ProxyPass 排除和仅no-proxy基于 REQUEST_URI 设置变量没有效果,因为 REQUEST_URI 在内部重写之后发生了变化,并且 ProxyPass 再次被评估,并且环境变量仅可见为REDIRECT_no-proxy不可见no-proxy

我们可以在这里使用一些小技巧,而且会起作用:

RewriteEngine on
RewriteRule ^/contact-us$ - [E=no-proxy:1]
RewriteCond %{ENV:REDIRECT_no-proxy} .+
RewriteRule .* - [E=no-proxy:1]

如果您将其放在 Virtual Host 部分,它将起作用。如果您将其放在 Directory 部分,则不会起作用,因为此时 ProxyPass 已经生效。

相关内容