如何在 .htaccess 中设置代理

问题描述 投票:0回答:2

Apache 文档指出 RewriteRule 和 应该放在服务器配置中,但由于共享主机情况,它们可以放在 htaccess 中。我就是这种情况。

我正在尝试设置透明代理:

 RewriteEngine On
 RewriteCond %{REQUEST_URI} ^/foo [OR]
 RewriteCond %{REQUEST_URI} ^/bar
 RewriteRule ^(.*)$ http://example.com/$1 [P]

这工作正常......除了重定向(比如如果

/foo
重定向到
/bar
)。重定向返回到 example.com,而不是我的服务器。

我知道

ProxyPassReverse
指令会解决这个问题,但是当我将它添加到
.htaccess

时,我得到一个“内部服务器错误”页面

与重写指令不同,

ProxyPassReverse
在 htaccess 中不起作用.

如何在共享主机情况下设置透明代理,或者这是不可能的?

(这似乎是合理的,因为 Rewrite 已经完成了 80%,并且在一个 htaccess 中拥有透明代理不会干扰在另一个 htaccess 中拥有它。)

apache .htaccess proxy transparentproxy
2个回答
24
投票

不幸的是,我很确定你想做的事情是不可能的:我正在尝试做同样的事情!根据我的研究,我相当有信心这是不可能的。

简而言之,您需要使用 ProxyPassReverse,它仅在 VirtualHost 级别(或类似级别)可用;不是 htaccess 级别。

编辑:我实现此目的的唯一方法是还配置响应服务器/应用程序以知道它在代理后面,并适当地提供页面。也就是说,我使用 .htaccess 重定向到另一台服务器,如下所示:

  RewriteEngine on
  RewriteRule  (.*)  http://localhost:8080/$1  [P,L] 

然后在应用程序服务器上——在本例中为 JIRA 安装——我适当地配置了 Java Tomcat/Catalina 以提供具有代理信息的页面:

 proxyName="my.public.address.com"
 proxyPort="80"

然而,这并不是完全透明的;应用程序服务器需要以代理方式提供页面。不过,它可能会有一些用处。


0
投票

我设法收集了一些资源来弄清楚如何做到这一点。我使用共享托管服务提供商,因此我无权访问服务器配置 (httpd.conf)。我只能使用 .htaccess 来完成代理。这个例子是针对一个 WordPress 网站的,我希望其中的大部分内容由 origin.example.com 提供,但会有一些页面在本地提供,有点像覆盖。你可以走另一条路,只使用不同的 RewriteCond 规则代理特定的子目录。

须知:

  1. 不能在.htaccess中使用ProxyPass或ProxyPassReverse,所以我们必须使用其他方法来模仿它们的作用。
  2. 如果您的供应商没有开启 SSLProxyEngine,您将无法通过 HTTPS 进行代理调用,因此如果您担心 MITM 攻击,您将失去一些安全性。如果原始服务器是内部服务器,这可能不是问题。您还可以在源服务器上使用 .htaccess 以从代理服务器以外的任何地方强制执行 HTTPS。
  3. 你需要重写标题
  4. 你需要重写从源服务器返回的HTML,并且需要在源服务器上完成。您可以将它限制为某些 IP(即代理的 IP),这样如果您在其他地方访问它就不会中断。

我想要的:

我想调用 proxy.example.com 来提供内容 origin.example.com。就我而言,除了少数例外,我想映射所有内容。如果您只想映射网站的一部分,请相应地调整规则。

怎么做:

  1. 在 proxy.example.com 上配置 .htaccess 文件,将所有 URI 代理到 origin.example.com。我希望能够登录到 proxy.example.com,所以我不重写 /wp-admin 或 /wp-login.php。在我的例子中,我有一个 /programs/ 部分,我希望代理服务器本身(也是一个 WordPress 实例)提供服务。通过检查 REDIRECT_STATUS 来防止循环。
# I force everything coming into proxy.example.com to be HTTPS <IfModule mod_rewrite.c>
RewriteEngine On

RewriteCond %{HTTP:X-Forwarded-Proto} !https
RewriteCond %{HTTPS} off
RewriteRule ^ https://%{HTTP_HOST}%{REQUEST_URI} [L,R=301] </IfModule> <IfModule mod_proxy.c>
# Redirect access for / (or any index) to the origin. NOTE target is http:// without SSLProxyEngine
RewriteCond %{ENV:REDIRECT_STATUS} ^$
RewriteRule ^(index\.(php|html|cgi))?$ http://origin.example.com/ [P]

# Do NOT redirect these patterns
RewriteCond %{REQUEST_URI} !^/wp-admin/
RewriteCond %{REQUEST_URI} !^/wp-login.php
RewriteCond %{REQUEST_URI} !^/programs/

# Redirect everything else. NOTE target is http:// without SSLProxyEngine
RewriteCond %{ENV:REDIRECT_STATUS} ^$
RewriteRule ^(.+)$ "http://origin.example.com/$1" [P]

# Mimic ProxyPassReverse. Fix the headers. Force to be https.
Header edit  Location ^https?://origin\.example\.com/(.*)$ https://proxy.example.com/$1
Header edit* Link https?://origin\.example\.com/ https://proxy.example.com/ </IfModule>
  1. 仅针对代理服务器的 IP,重写 HTML 本身中的任何引用。此示例适用于 WordPress 网站。

WordPress 过滤器中窃取以修改最终的 html 输出

2a) 添加必须使用的插件以添加“final_output”挂钩。在 wp-content/mu-plugins/buffer.php 添加一个文件:

<?php

/**  * Output Buffering  *  * Buffers the entire WP process, capturing
the final output for manipulation.  */

ob_start();

add_action('shutdown', function() {
    $final = '';

    // We'll need to get the number of ob levels we're in, so that we can iterate over each, collecting
    // that buffer's output into the final output.
    $levels = ob_get_level();

    for ($i = 0; $i < $levels; $i++) {
        // NOTE: Use only one of the two lines below
        // that has your output come out in the correct order.
        //$final .= ob_get_clean();
        $final = ob_get_clean() . $final;
    }

    // Apply any filters to the final output
    echo apply_filters('final_output', $final); }, 0); ?>

2b) 将以下 PHP 添加到 wp-content/themes/yourthemenamehere/functions.php。它使用上面的“final_output”挂钩。 (使用匿名函数需要 PHP 5.3 或更高版本。)

add_filter('final_output', function($output) {
    // IP of the proxy server
    $WWW_IP = “4.4.4.4”; 
    //$WWW_IP = “4.4.2.2”;  // My workstation, for testing purpose only
    if ($_SERVER['REMOTE_ADDR'] == $WWW_IP) {
        // Force HTTPS when rewriting
        $output = str_replace('http://origin.example.com', 'https://proxy.example.com’, $output);
        // Catch anything that wasn’t a URL
        return str_replace(‘origin.example.com, 'proxy.example.com', $output);
    }
    return $output;
});

如果一切顺利,您现在应该可以看到来自 origin.example.com 的内容由 proxy.example.com 提供。

我还在测试这个,所以如果你发现错误或遗漏,请添加评论。

© www.soinside.com 2019 - 2024. All rights reserved.