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 @@
<<SAMP>http://wibble.org/mirror/foo/bar</SAMP>> to be
internally converted into a proxy request to
<<SAMP>http://foo.com/bar</SAMP>>.
+
+<HR>
+
+<H2><A NAME="proxypassreverse">ProxyPassReverse</A></H2>
+<A
+ HREF="directive-dict.html#Syntax"
+ REL="Help"
+><STRONG>Syntax:</STRONG></A> ProxyPassReverse <EM><path> <url></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.
+<path> is the name of a local virtual path; <url> 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
+<<SAMP>http://wibble.org/mirror/foo/bar</SAMP>> to be
+internally converted into a proxy request to
+<<SAMP>http://foo.com/bar</SAMP>> (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