You are viewing a plain text version of this content. The canonical link for it is here.
Posted to dev@httpd.apache.org by "Ralf S. Engelschall" <rs...@engelschall.com> on 1998/02/12 16:03:05 UTC

[PATCH] Apache as a Reverse Proxy

Apache as a Reverse Proxy
-------------------------

Because I'm currently writing an article for WebTechniques where I present a
stripped down Apache (only mod_rewrite+mod_proxy(+mod_mime :-( ) and no other
modules compiled in) which acts a high-performance reverse proxy in front of a
website cluster, I discovered that one really _essential_ feature is missing -
the following patch adds it: A ProxyPassReverse directive for mod_proxy !

Read the HTML snippet in the below patch to understand what is does.  In
short: It rewrites the Location-header on redirect responses so the reverse
proxy is still in the game...

(PS: I don't patches mod_proxy for any content rewriting because I 
     think when someone uses a reverse proxy he should know that his CGI
     scripts and HTML pages either only use non-fully-qualified URLs or at
     least use http://name-of-the-reverse-proxy/ as the prefix)

(PPS: Yes, I know that for the request spreading a reverse proxy
     also needs some way of randomly select its backend-servers
     and that Apache currently is missing this feature, too.
     But I've also already done this: See the recent patch for
     mod_rewrite which adds a RewriteMap type named "rnd" which
     is designed exctly for this! These two patches together
     lets act Apache as a full-featured high-performance Reverse
     Proxy.  The special configuration I will present in the
     article or on apache-core when someone is interested in)

Greetings,
                                       Ralf S. Engelschall
                                       rse@engelschall.com
                                       www.engelschall.com

Index: htdocs/manual/mod/mod_proxy.html
===================================================================
RCS file: /e/apache/REPOS/apache-1.3/htdocs/manual/mod/mod_proxy.html,v
retrieving revision 1.34
diff -u -r1.34 mod_proxy.html
--- mod_proxy.html	1998/02/05 22:34:05	1.34
+++ mod_proxy.html	1998/02/12 14:48:15
@@ -43,6 +43,7 @@
 <LI><A HREF="#proxyrequests">ProxyRequests</A>
 <LI><A HREF="#proxyremote">ProxyRemote</A>
 <LI><A HREF="#proxypass">ProxyPass</A>
+<LI><A HREF="#proxypass">ProxyPassReverse</A>
 <LI><A HREF="#proxyblock">ProxyBlock</A>
 <LI><A HREF="#noproxy">NoProxy</A>
 <LI><A HREF="#proxydomain">ProxyDomain</A>
@@ -197,6 +198,65 @@
 &lt;<SAMP>http://wibble.org/mirror/foo/bar</SAMP>&gt; to be
 internally converted into a proxy request to
 &lt;<SAMP>http://foo.com/bar</SAMP>&gt;.
+
+<HR>
+
+<H2><A NAME="proxypassreverse">ProxyPassReverse</A></H2>
+<A
+ HREF="directive-dict.html#Syntax"
+ REL="Help"
+><STRONG>Syntax:</STRONG></A> ProxyPassReverse <EM>&lt;path&gt; &lt;url&gt;</EM><BR>
+<A
+ HREF="directive-dict.html#Default"
+ REL="Help"
+><STRONG>Default:</STRONG></A> <EM>None</EM><BR>
+<A
+ HREF="directive-dict.html#Context"
+ REL="Help"
+><STRONG>Context:</STRONG></A> server config, virtual host<BR>
+<A
+ HREF="directive-dict.html#Override"
+ REL="Help"
+><STRONG>Override:</STRONG></A> <EM>Not applicable</EM><BR>
+<A
+ HREF="directive-dict.html#Status"
+ REL="Help"
+><STRONG>Status:</STRONG></A> Base<BR>
+<A
+ HREF="directive-dict.html#Module"
+ REL="Help"
+><STRONG>Module:</STRONG></A> mod_proxy<BR>
+<A
+ HREF="directive-dict.html#Compatibility"
+ REL="Help"
+><STRONG>Compatibility:</STRONG></A> ProxyPassReverse is only available in
+Apache 1.3 and later.<P>
+
+This directive lets Apache adjust the URL in the <TT>Location</TT> header on
+redirect responses. This is for instance essential when Apache is used as a
+reverse proxy. But can be a nifty trick in other situations, too.
+&lt;path&gt; is the name of a local virtual path; &lt;url&gt; is a partial URL
+for the remote server - the same way they are used for the
+<TT>ProxyPass</TT> directive.
+<P>
+Suppose the local server has address <SAMP>http://wibble.org/</SAMP>; then
+<PRE>
+   ProxyPass         /mirror/foo http://foo.com
+   ProxyPassReverse  /mirror/foo http://foo.com
+</PRE>
+will not only cause a local request for the
+&lt;<SAMP>http://wibble.org/mirror/foo/bar</SAMP>&gt; to be
+internally converted into a proxy request to
+&lt;<SAMP>http://foo.com/bar</SAMP>&gt; (the functionality
+<SAMP>ProxyPass</SAMP> provides here). It also takes care of redirects the
+server foo.com sends: when <SAMP>http://foo.com/bar</SAMP> is redirected by him
+to <SAMP>http://foo.com/quux</SAMP> Apache adjusts this to
+<SAMP>http://wibble.org/mirror/foo/quux</SAMP> before forwarding the redirect
+reponse to the client. The <SAMP>ProxyPassReverse</SAMP> directive can also by
+used in conjunction with a ``<SAMP>RewriteRule .. ... [P]</SAMP>'' directive from
+<A
+ HREF="mod_rewrite.html#RewriteRule"
+><TT>mod_rewrite</TT></A>.
 
 <HR>
 
Index: src/modules/proxy/mod_proxy.c
===================================================================
RCS file: /e/apache/REPOS/apache-1.3/src/modules/proxy/mod_proxy.c,v
retrieving revision 1.35
diff -u -r1.35 mod_proxy.c
--- mod_proxy.c	1998/02/02 22:33:38	1.35
+++ mod_proxy.c	1998/02/12 14:32:21
@@ -379,6 +379,7 @@
 
     ps->proxies = make_array(p, 10, sizeof(struct proxy_remote));
     ps->aliases = make_array(p, 10, sizeof(struct proxy_alias));
+    ps->raliases = make_array(p, 10, sizeof(struct proxy_alias));
     ps->noproxies = make_array(p, 10, sizeof(struct noproxy_entry));
     ps->dirconn = make_array(p, 10, sizeof(struct dirconn_entry));
     ps->nocaches = make_array(p, 10, sizeof(struct nocache_entry));
@@ -455,6 +456,20 @@
 }
 
 static const char *
+     add_pass_reverse(cmd_parms *cmd, void *dummy, char *f, char *r)
+{
+    server_rec *s = cmd->server;
+    proxy_server_conf *conf =
+    (proxy_server_conf *) get_module_config(s->module_config, &proxy_module);
+    struct proxy_alias *new;
+
+    new = push_array(conf->raliases);
+    new->fake = f;
+    new->real = r;
+    return NULL;
+}
+
+static const char *
      set_proxy_exclude(cmd_parms *parms, void *dummy, char *arg)
 {
     server_rec *s = parms->server;
@@ -727,6 +742,8 @@
      "a scheme, partial URL or '*' and a proxy server"},
     {"ProxyPass", add_pass, NULL, RSRC_CONF, TAKE2,
      "a virtual path and a URL"},
+    {"ProxyPassReverse", add_pass_reverse, NULL, RSRC_CONF, TAKE2,
+     "a virtual path and a URL for reverse mapping"},
     {"ProxyBlock", set_proxy_exclude, NULL, RSRC_CONF, ITERATE,
    "A list of names, hosts or domains to which the proxy will not connect"},
     {"NoProxy", set_proxy_dirconn, NULL, RSRC_CONF, ITERATE,
Index: src/modules/proxy/mod_proxy.h
===================================================================
RCS file: /e/apache/REPOS/apache-1.3/src/modules/proxy/mod_proxy.h,v
retrieving revision 1.26
diff -u -r1.26 mod_proxy.h
--- mod_proxy.h	1998/01/07 16:46:35	1.26
+++ mod_proxy.h	1998/02/12 14:32:26
@@ -191,6 +191,7 @@
     struct cache_conf cache;	/* cache configuration */
     array_header *proxies;
     array_header *aliases;
+    array_header *raliases;
     array_header *noproxies;
     array_header *dirconn;
     array_header *nocaches;
Index: src/modules/proxy/proxy_http.c
===================================================================
RCS file: /e/apache/REPOS/apache-1.3/src/modules/proxy/proxy_http.c,v
retrieving revision 1.37
diff -u -r1.37 proxy_http.c
--- proxy_http.c	1998/02/02 22:33:38	1.37
+++ proxy_http.c	1998/02/12 14:32:32
@@ -56,6 +56,7 @@
 #include "mod_proxy.h"
 #include "http_log.h"
 #include "http_main.h"
+#include "http_core.h"
 #include "util_date.h"
 
 /*
@@ -113,6 +114,28 @@
 		   path, (search) ? "?" : "", (search) ? search : "", NULL);
     return OK;
 }
+ 
+static char *proxy_location_reverse_map(request_rec *r, char *url)
+{
+    void *sconf;
+    proxy_server_conf *conf;
+	struct proxy_alias *ent;
+    int i, l1, l2;
+	char *u;
+
+    sconf = r->server->module_config;
+    conf = (proxy_server_conf *)get_module_config(sconf, &proxy_module);
+    l1 = strlen(url);
+	ent = (struct proxy_alias *)conf->raliases->elts;
+    for (i = 0; i < conf->raliases->nelts; i++) {
+        l2 = strlen(ent[i].real);
+        if (l1 >= l2 && strncmp(ent[i].real, url, l2) == 0) {
+            u = pstrcat(r->pool, ent[i].fake, &url[l2], NULL);
+            return construct_url(r->pool, u, r);
+        }
+    }
+    return url;
+}
 
 /* Clear all connection-based headers from the incoming headers table */
 static void clear_connection(table *headers)
@@ -365,6 +388,9 @@
 	    strcasecmp(strp, "Last-Modified") == 0 ||
 	    strcasecmp(strp, "Expires") == 0)
 	    hdr[i].value = proxy_date_canon(p, hdr[i].value);
+	if (strcasecmp(strp, "Location") == 0 ||
+	    strcasecmp(strp, "URI") == 0)
+	    hdr[i].value = proxy_location_reverse_map(r, hdr[i].value);
     }
 
 /* check if NoCache directive on this host */
                                       Ralf S. Engelschall
                                       rse@engelschall.com
                                       www.engelschall.com

Re: [PATCH] Apache as a Reverse Proxy

Posted by Martin Kraemer <Ma...@mch.sni.de>.
On Thu, Feb 12, 1998 at 04:03:05PM +0100, Ralf S. Engelschall wrote:
> Index: htdocs/manual/mod/mod_proxy.html
> ===================================================================
> RCS file: /e/apache/REPOS/apache-1.3/htdocs/manual/mod/mod_proxy.html,v
> retrieving revision 1.34
> diff -u -r1.34 mod_proxy.html
> --- mod_proxy.html	1998/02/05 22:34:05	1.34
> +++ mod_proxy.html	1998/02/12 14:48:15
> @@ -43,6 +43,7 @@
>  <LI><A HREF="#proxyrequests">ProxyRequests</A>
>  <LI><A HREF="#proxyremote">ProxyRemote</A>
>  <LI><A HREF="#proxypass">ProxyPass</A>
> +<LI><A HREF="#proxypass">ProxyPassReverse</A>
		 ^^^^^^^^^proxypassreverse

+1 otherwise (but untested)

    Martin
-- 
| S I E M E N S |  <Ma...@mch.sni.de>  |      Siemens Nixdorf
| ------------- |   Voice: +49-89-636-46021     |  Informationssysteme AG
| N I X D O R F |   FAX:   +49-89-636-44994     |   81730 Munich, Germany
~~~~~~~~~~~~~~~~My opinions only, of course; pgp key available on request

Re: [PATCH] Apache as a Reverse Proxy

Posted by Brian Behlendorf <br...@organic.com>.
old mail day!

At 04:03 PM 2/12/98 +0100, Ralf S. Engelschall wrote:
>Apache as a Reverse Proxy

I see this got implemented; great!  One question though, why two separate
directives, "ProxyPass" and "ProxyPassReverse"?  What situation would one
specify a ProxyPass section of their site, and *not* want the
redirect-rewriting that PPR does?  I suggest in the interests of directive
simplicity that the functionality of PPR be merged into the code for
ProxyPass.

	Brian


--=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=--
specialization is for insects				  brian@organic.com