12.10 Frontend/Backend Proxying with Virtual Hosts
This section explains a configuration setup for proxying your backend
mod_perl servers when you need to use virtual hosts.
12.10.1 Virtual Host Flavors
Apache supports three flavors of virtual
hosts:
- IP-based virtual hosts
-
In this form, each virtual host uses its own IP address. Under Unix,
multiple IP addresses are assigned to the same network interface
using the ifconfig utility. These additional IP
addresses are sometimes called virtual addresses
or IP aliases. IP-based virtual hosting is the
oldest form of virtual hosting. Due to the supposed increasing
scarcity of IP addresses and ensuing difficulty in obtaining large
network blocks in some parts of the world, IP-based virtual hosting
is now less preferred than name-based virtual hosting.
- Name-based virtual hosts
-
Name-based virtual hosts share a single IP address. Apache dispatches
requests to the appropriate virtual host by examining the
Host: HTTP header field. This
field's value is the hostname extracted from the
requested URI. Although this header is mandatory for HTTP 1.1
clients, it has also been widely used by HTTP 1.0 clients for many
years.
- Port-based virtual hosts
-
In this setup, all virtual hosts share the same IP address, but each
uses its own unique port number. As we'll discuss in
the next section, port-based virtual hosts are mostly useful for
backend servers not directly accessible from Internet clients.
- Mixed flavors
-
It is perfectly possible to mix the various virtual host flavors in
one server.
12.10.2 Dual-Server Virtual Host Configuration
In the dual-server setup, which virtual host flavor is used
on the frontend (reverse proxy) server is irrelevant. When running a
large number of virtual hosts, it is generally preferable to use
name-based virtual hosts, since they share a single IP address. HTTP
clients have been supporting this since 1995.
SSL-enabled sites cannot use this scheme, however. This is because
when using SSL, all HTTP traffic is encrypted, and this includes the
request's Host: header. This
header is unavailable until the SSL handshake has been performed, and
that in turn requires that the request has been dispatched to the
appropriate virtual host, because the SSL handshake depends on that
particular host's SSL certificate. For this reason,
each SSL-enabled virtual host needs its own, unique IP address. You
can still use name-based virtual hosts along with SSL-enabled virtual
hosts in the same configuration file, though.
For the backend mod_perl-enabled server, we recommend using
port-based virtual hosts using the IP address 127.0.0.1
(localhost). This enforces the fact that this
server is accessible only from the frontend server and not directly
by clients.
12.10.3 Virtual Hosts and Main Server Interaction
When using virtual hosts, any configuration directive outside
of a <VirtualHost> container is applied to a
virtual host called the main server, which plays
a special role. First, it acts as the default host when
you're using name-based virtual hosts and a request
can't be mapped to any of the configured virtual
hosts (for example, if no Host: header is
provided). Secondly, many directives specified for the main server
are merged with directives provided in
<VirtualHost> containers. In other words,
virtual hosts inherit properties from the main server. This allows us
to specify default behaviors that will apply to all virtual hosts,
while still allowing us to override these behaviors for specific
virtual hosts.
In the following example, we use the PerlSetupEnv
directive to turn off environment population for all virtual hosts,
except for the www.example.com virtual host,
which needs it for its legacy CGI scripts running under
Apache::Registry:
PerlSetupEnv Off
Listen 8001
<VirtualHost 127.0.0.1:8001>
ServerName www.example.com
PerlSetupEnv On
</VirtualHost>
12.10.4 Frontend Server Configuration
The following example illustrates the use of
name-based virtual hosts. We define two virtual hosts,
www.example.com and
www.example.org, which will reverse-proxy
dynamic requests to ports 8001 and 8002 on the backend
mod_perl-enabled server.
Listen 192.168.1.2:80
NameVirtualHost 192.168.1.2:80
Replace 192.168.1.2 with your server's public IP
address.
LogFormat "%v %h %l %u %t \"%r\" %s %b \"%{Referer}i\" \"%{User-agent}i\""
The log format used is the Common Log Format prefixed with
%v, a token representing the name of the virtual
host. Using a combined log common to all virtual hosts uses fewer
system resources. The log file can later be split into seperate files
according to the prefix, using splitlog or an
equivalent program.
The following are global options for mod_rewrite shared by all
virtual hosts:
RewriteLogLevel 0
RewriteRule \.(gif|jpg|png|txt|html)$ - [last]
This turns off the mod_rewrite module's logging
feature and makes sure that the frontend server will handle files
with the extensions .gif,
.jpg, .png,
.txt, and .html internally.
If your server is configured to run traditional CGI scripts (under
mod_cgi) as well as mod_perl CGI programs, it would be beneficial to
configure the frontend server to run the traditional CGI scripts
directly. This can be done by altering the
(gif|jpg|png|txt|html) rewrite rule to add
cgi if all your mod_cgi scripts have the
.cgi extension, or by adding a new rule to
handle all /cgi-bin/* locations internally.
The virtual hosts setup is straightforward:
##### www.example.com
<VirtualHost 192.168.1.2:80>
ServerName www.example.com
ServerAdmin webmaster@example.com
DocumentRoot /home/httpd_docs/htdocs/www.example.com
RewriteEngine on
RewriteOptions 'inherit'
RewriteRule ^/(perl/.*)$ http://127.0.0.1:8001/$1 [P,L]
ProxyPassReverse / http://www.example.com/
</VirtualHost>
##### www.example.org
<VirtualHost 192.168.1.2:80>
ServerName www.example.org
ServerAdmin webmaster@example.org
DocumentRoot /home/httpd_docs/htdocs/www.example.org
RewriteEngine on
RewriteOptions 'inherit'
RewriteRule ^/(perl/.*)$ http://127.0.0.1:8002/$1 [P,L]
ProxyPassReverse / http://www.example.org/
</VirtualHost>
The two virtual hosts' setups differ in the
DocumentRoot and
ProxyPassReverse settings and in the backend ports
to which they rewrite.
12.10.5 Backend Server Configuration
This section describes the configuration of the
backend server.
The backend server listens on the loopback
(localhost) interface:
BindAddress 127.0.0.1
In this context, the following directive does not specify a listening
port:
Port 80
Rather, it indicates which port the server should advertise when
issuing a redirect.
The following global mod_perl settings are shared by all virtual
hosts:
##### mod_perl settings
PerlRequire /home/httpd/perl/startup.pl
PerlFixupHandler Apache::SizeLimit
PerlPostReadRequestHandler Book::ProxyRemoteAddr
PerlSetupEnv Off
As explained earlier, we use the
Book::ProxyRemoteAddr handler to get the
real remote IP addresses from the proxy.
We can then proceed to configure the virtual hosts themselves:
##### www.example.com
Listen 8001
<VirtualHost 127.0.0.1:8001>
The Listen directive specifies the port to listen
on. A connection to that port will be matched by this
<VirtualHost> container.
The remaining configuration is straightforward:
ServerName www.example.com
ServerAdmin webmaster@example.com
<Location /perl>
SetHandler perl-script
PerlHandler Apache::Registry
Options +ExecCGI
</Location>
<Location /perl-status>
SetHandler perl-script
PerlHandler Apache::Status
</Location>
</VirtualHost>
We configure the second virtual host in a similar way:
##### www.example.org
Listen 8002
<VirtualHost 127.0.0.1:8002>
ServerName www.example.org
ServerAdmin webmaster@example.org
<Location /perl>
SetHandler perl-script
PerlHandler Apache::Registry
Options +ExecCGI
</Location>
</VirtualHost>
You may need to specify the DocumentRoot setting
in each virtual host if there is any need for it.
|