You are not logged in Log in Join
You are here: Home » Members » anser » Using Apache with ZServer (NOT Zope.cgi)

Log in
Name

Password

 

Using Apache with ZServer (NOT Zope.cgi)

New: a complete solution using SiteAccess!

The existing How-To's for combining Zope with the popular Apache server mostly require you to use the CGI interface to Zope, instead of the much faster, multithreaded ZServer. This incurs a big penalty in startup overhead for each run of the CGI, and it forces single threading of the Zope database.

On the other hand, running ZServer alone isn't always practical! Versatile Apache is much better for serving legacy HTML/CGI content, it's often intricately configured in ways that are hard to achieve in ZServer, and even if you want to, you may not be allowed for business or other reasons.

Fortunately, it's easy to embed ZServer behind Apache, using the ProxyPass and ProxyPassReverse configuration directives from Apache's mod_proxy. Your ZServer can run on the same machine as Apache, or some other machine - it doesn't matter! A load balanced "farm" of front-line Apache servers can share a ZServer. There are lots of possibilities, but let's look at how we work this miracle.

What does ProxyPass do?

Apache's ProxyPass directive implements what is known as an "inverse proxy," where one server sits in front of another and "hides" the back server's content by accepting requests, massaging the URL, passing it to the back server, waiting for a response, and handing it back to the client. This technique has many uses: in-house corporate servers with no direct Internet access can serve limited content to the outside world by masquerading behind a public server with a ProxyPass directive; load-balanced and fault tolerant "server farms" can serve clients through a massively cached front end box; and so forth.

There are actually two directives:

ProxyPass /visiblepath http://backserver:port/path...

This intercepts incoming client requests beginning with /visiblepath (interpreted as a Location, not a Directory), strips that part off, prepends http://backserver:port/path... instead, goes to backserver:port to satisy the request, then returns the result to the client as though it had come from Apache's own document tree.

ProxyPassReverse /visiblepath http://backserver:port/path...

This matching directive watches in the other direction! URL Redirects from backserver:port, and other responses containing a URL in the header, are automatically back-translated to begin with /visiblepath instead, so the "illusion" is preserved. Otherwise simple redirects within the backserver would immediately "break" the inverse proxy. But note that this back-translation does not extend to the document body! This will come back to haunt us below. But for now, we are ready to talk to ZServer via ProxyPass.

First example: Partial Zope-ification

Let's say that we host the website http://www.fightclub.org, using Apache 1.3 on good old port 80, and we want to add a Zope area at http://www.fightclub.org/Zope, without affecting any of the legacy content that's already online. We install Zope on the machine, and set up ZServer to listen to port 8080.

First, we have to make sure that Apache's mod_proxy is configured and activated, so we check the following lines in httpd.conf or apache.conf:

LoadModule proxy_module libexec/apache/libproxy.so
AddModule mod_proxy.c

Now we add our inverse proxy directives, within the main <Directory> context:

ProxyPass /Zope/ http://fightclub.org:8080/
ProxyPassReverse /Zope/ http://fightclub.org:8080/

Restart Apache and that's almost it! Every request to http://www.fightclub.org/Zope/* will get passed through to the ZServer, while all other content remains under Apache's control as before.

But there is one problem: Zope's emitted HTML is thickly laced with absolute URL HREF's containing the exact machine and port that Zope thinks it's running on. There is a forest of HTTP environment variables and DTML variables forcing the backserver:port info into the body of the document, where ProxyPassReverse can't get at it. The result is that part or all of your page, linked subpages, embedded graphics, etc, won't load -- a big mess.

And you can't use the clever solution (Apache's SetEnv directive) Dave Parker came up with for the people using CGI and mod_rewrite, in his How-To on dynamic host names, because environment variables aren't passed across the internal proxy "pipeline" to ZServer!

Fortunately there is an elegant solution: add Evan Simpson's SiteAccess product into your Zope installation. SiteAccess lets you add a SiteRoot object into any Folder (or subclass thereof): the SiteRoot defines a Base that replaces the URL stem in all the absolute URL's generated by Zope at and below that folder. After installing SiteAccess, restart ZServer and manage your content folder. Add a SiteRoot object and edit its fields as follows:

Title
Base
Path

Now you are really in business. Users can access http://www.fightclub.org/Zope/ and they see your Zope content as served by ZServer. Bliss.

You can even do content management through the Apache proxy! ( http://www.fightclub.org/Zope/manage ) But when you do, there is one tiny annoyance left: the icon graphics for the object tree don't load. (That's because they are being loaded by plain old IMG SRC="/misc_/xxx_image" tags - no site_url DTML variable for SiteAccess to fix.) To fix this, go back to Apache and add two more ProxyPass directives, next to the ones you already entered:

ProxyPass /misc_ http://fightclub.org:8080/misc_
ProxyPass /p_ http://fightclub.org:8080/p_

(You don't need matching ProxyPassReverse directives.) This sends client requests for images in /p_ and /misc_ through to the ZServer as well... which shouldn't be a problem unless your legacy content already included root directories with those names!

Tip: To see the HTTP environment Zope is passed, put this in a DTML method and view it:

<pre>
REQUEST: <dtml-var REQUEST>
</pre>

Second example: a complete virtual host

All right, now suppose we are using Apache to run a bunch of virtual hosts (very popular nowadays) and we want to set up fightclub.org again, this time as an all-Zope site, without affecting our other virtual host clients. We'll use named virtual hosts on an Apache 1.3 server at port 80 of IP address 192.192.123.234.

Just to show the versatility of this approach, let's put the ZServer we want to proxy to on a separate machine, port 9180 of zserver.xyz.com. That external ZServer will contain content for many clients, with the fightclub.org material rooted in the Zope Folder /fightclub. We make sure it has the SiteAccess product installed.

OK, first the Apache config file. If you don't understand virtual hosts, see the Apache docs.

LoadModule proxy_module libexec/apache/libproxy.so
AddModule mod_proxy.c
...

NameVirtualHost 192.192.123.234

<VirtualHost 192.192.123.234>
ServerName www.fightclub.org
ServerAdmin tyler@fightclub.org

ProxyPass / http://zserver.xyz.com:9180/fightclub/
ProxyPassReverse / http://zserver.xyz.com:9180/fightclub/
ProxyPass /misc_ http://zserver.xyz.com:9180/misc_
ProxyPass /p_ http://zserver.xyz.com:9180/p_

</VirtualHost>

Now we can restart Apache, and visit the management interface for our ZServer at http://zserver.xyz.com:9180/fightclub/manage . In the /fightclub Folder, we add a SiteRoot object, and edit its fields:

Title
Base
Path

As soon as that change is made, proxy access ought to work! Note: you will probably want to exit your browser and restart it after changing SiteRoot, because the client can get confused about authentication!

In conclusion

My thanks to Evan Simpson and to the Zope and Apache teams for their great work!

--
anser