Getting Started
Before you can set up virtual hosting in Zope, you need to answer two questions:
- What is the URI of each site's logical root?
- What is the corresponding path to the physical root?
Suppose, for example, that you want to use Zope to host the domain www.hotsite.com,
and you want 'http://www.hotsite.com' to publish the Zope object '/hotsite/index_html'.
Then 'http://www.hotsite.com' is the URI of your logical root, and '/hotsite' is the
path to your physical root.
Example 1: One Site
Put a SiteRoot in '/hotsite', your site's physical root, and accept the
default Path. Create a DTML Method in the Zope root folder containing
Is the first-level domain 'hotsite.com'? Ignore sub-domains and port number.
<dtml-if "_.string.split(_.string.split(HTTP_HOST, ':')[0], '.')[-2:]==['hotsite', 'com']">
Add physical root:
<dtml-call "REQUEST['TraversalRequestNameStack'].append('hotsite')">
</dtml-if >
Use "Set Access Rule" with the DTML Method's Id. Want to understand this? Read on.
Getting Physical
The first half of virtual hosting is rewriting incoming URIs into physical
paths. Many people run ZServer behind Apache, or another HTTP server with
rewriting capabilities, or a proxy. In these cases, you can tell the
front-end HTTP server to rewrite 'http://www.hotsite.com/(.*)' to
'/blah/cgi/Zope.cgi/hotsite/$1', for example.
This works perfectly well, but if your clients are connecting directly to
ZServer, or if you would like to keep all of the virtual hosting logic
in Zope, you will need to do your rewriting in an Access Rule.
An Access Rule is just a regular method (DTML Method or Document, External
Method, Python Method, etc.) on which you have used SiteAccess'
"Set Access Rule" method. In this case, the method lives in the root, so it
will examine every incoming request and decide how to deal with it.
The example DTML Method above is the simplest kind of rewrite rule, forcing
all requests to traverse the 'hotsite' object before any others in the URI.
Getting Logical
The second, and more difficult, half of virtual hosting is getting your Zope
objects to generate correct logical URIs for links and images. For example,
if you are rewriting hotsite as described above, then a standard DTML snippet
such as
<a href="&dtml-URL;/hottopics">
in object '/hotsite/forum' will generate
<a href="http://www.hotsite.com/hotsite/forum/hottopics">
rather than
<a href="http://www.hotsite.com/forum/hottopics">
To prevent this, all of the URLn and BASEn request variables and the
absolute_url() method need to be told to strip off '/hotsite'. That's what
SiteRoot objects do.
A SiteRoot object should be placed in the physical root folder ('/hotsite', in
this case) and told the logical URL at which to base all requests passing
through this folder. You tell it by setting its Path property, which in this
case should have the value '/'.
For flexibility's sake, Path can also be set
as a property 'SiteRootPATH' of the '/hotsite' folder or of the root folder,
or it can be set in the rewriting Access Rule with a call to
"REQUEST.set('SiteRootPATH', '/')", or it can be passed in from the
mediating web server as an environment variable. You can also provide
a Base ('SiteRootBASE') value, which will then replace the host:port/script
portion of URIs.
Example 2: Multiple Sites
Suppose we are hosting 'hotsite.net', 'fooflowers.com', and 'openmouths.org'
from '/hotsite', '/foof', and '/openm' respectively. We are distinguishing
requests via HTTP_HOST, and we don't care what subdomain or port was specified.
Put a SiteRoot in each of '/hotsite', '/foof', and '/openm'.
In each one, erase the default Path and leave Base blank.
Make a DTML Method in the root folder containing
Extract the part of HTTP_HOST we care about, and declare our rewrite dictionary.
<dtml-let hostname="_.string.join(_.string.split(_.string.split(HTTP_HOST, ':')[0], '.')[-2:], '.')"
sitemap="{'hotsite.net': 'hotsite',
'fooflowers.com': 'foof',
'openmouths.org': 'openm'}">
Do we have a match?
<dtml-if expr="sitemap.has_key(hostname)">
Set the logical root: <dtml-call "REQUEST.set('SiteRootPATH', '/')">
Add physical root: <dtml-call "REQUEST['TraversalRequestNameStack'].append(sitemap[hostname])">
</dtml-if>
</dtml-let>
Use "Set Access Rule" with the DTML Method's Id. An almost identical method
can be used to distinguish sites by SERVER_ADDRESS and SERVER_PORT instead
of HTTP_HOST. In that case, though, you would probably add a line to set the
appropriate SiteRootBASE.
If you wanted all of these virtual hosts' root folders to live in the folder
'vhosts', you could add the line:
Add vhost root: <dtml-call "REQUEST['TraversalRequestNameStack'].append('vhosts')">
after the 'Add physical root' line. If you wanted to add multiple path
elements for each site, you could use path.extend instead of path.append and
map 'fooflowers.org', for example, to ['foof', 'f', 'comsites']. This would
place the root of fooflowers in folder '/comsites/f/foof/'.
Minor Notes