2

I use Apache as a reverse proxy. There is no web content on the dedicated server itself. If a client requests a resource on the local Apache server, Apache should determine on which remote (proxied) server the resource exists and do a proxy rewrite to that server.

A snippet should (that currently does not work) should demonstrate, what i would do:

RewriteCond               http://200.202.204.11:3000%{REQUEST_URI}    -U
RewriteRule     ^(.*)$    http://200.202.204.11:3000$1                [P]

I spared out the rest of my configuration (ProxyPass, ProxyPassReverse, other RewriteCond,...) to focus on my problem:

How could I check if an external resource exists / is available before rewriting?

The -U option for RewriteCond returns alwas true. The -F option returns alwas false. Is there a working solution for my intent?

Thomas Steinbach
  • 1,019
  • 1
  • 9
  • 19

2 Answers2

0

After searching for weeks to get the solution I come to the conclusion: there is no reliable RewriteRule if an external ressource exists.

You go much better if you address your service behind an reverse proxy via subdomains. E.g. 'gitlab.youdomain.net' if you want to address a ressource on your gitlab server behind your reverse proxy. So the reverse proxy does not become confused if the ressource is lying in the root directory '/' of the gitlab server.

Thomas Steinbach
  • 1,019
  • 1
  • 9
  • 19
0

I had the same problem but, as far as I know, I got same results: it is not possible do it using only Apache httpd directives (at least with the version 2.2).
In my solution I did it using a RewriteMap and a PHP script able to check if the external resource exists.

In this example, when a new request comes, RewriteMap check the existence of requested path on Server A and, if successfully found, it reverse proxy the request on same server. On the other hand, if the requested path is not found on Server A, it implements a rewrite rule to reverse proxy the request on serverB.

As said, I have used a RewriteMap with MapType prg: and a PHP script. Here the Apache directives:

# Please pay attention to RewriteLock
# this directive must be defined in server config context
RewriteLock /tmp/if_url_exists.lock

RewriteEngine On

ProxyPreserveHost Off
ProxyRequests Off

RewriteMap  url_exists "prg:/usr/bin/php /opt/local/scripts/url_exists.php"
RewriteCond ${url_exists:http://serverA%{REQUEST_URI}}   >0
RewriteRule .            http://serverA%{REQUEST_URI} [P,L]

RewriteRule .            http://serverB%{REQUEST_URI} [P,L]

Here comes the interesting and tricky part. This is the url_exists.php script, executed by Apache. It is waiting on the standard input stream and write into standard output. This scripts return 1 if the resource is found and readable, otherwise 0. It is so light even because it implements only an HTTP request using the HEAD method.

<?php

function check_if_url_exists($line) {
    $curl_inst = curl_init($line);
    curl_setopt( $curl_inst, CURLOPT_CONNECTTIMEOUT, 30);
    curl_setopt( $curl_inst, CURLOPT_LOW_SPEED_LIMIT, 1);
    curl_setopt( $curl_inst, CURLOPT_LOW_SPEED_TIME, 180);
    curl_setopt( $curl_inst, CURLOPT_HEADER, true);
    curl_setopt( $curl_inst, CURLOPT_FAILONERROR, true);
    // Exclude the body from the output and request method is set to HEAD.
    curl_setopt( $curl_inst, CURLOPT_NOBODY, true);
    curl_setopt( $curl_inst, CURLOPT_FOLLOWLOCATION, true);
    curl_setopt( $curl_inst, CURLOPT_RETURNTRANSFER, true);
    $raw = curl_exec($curl_inst);
    curl_close($curl_inst);
    return ($raw != false) ? true : false;
}

set_time_limit(0);
$keyboard = fopen("php://stdin","r");

while (true) {
    $line = trim(fgets($keyboard));
    if (!empty($line)) {
        $str = (check_if_url_exists($line)) ? "1" : "0";
        echo $str."\n";
    }
}
freedev
  • 25,946
  • 8
  • 108
  • 125