Using Apache ProxyPass to access servers behind a Masquarading host

ArticleCategory: [Choose a category for your article]

System Administration

AuthorImage:[Here we need a little image form you]

[Photo of the Author]

TranslationInfo:[Author and translation history]

original in en Atif Ghaffar 

AboutTheAuthor:[A small biography about the author]

I live and work in Switzerland as a webmaster and unix administrator. My passions include, Linux, unix, Perl, Apache and GPL softwares. More about me can be found on my homepage

Abstract:[Here you write a little summary]

I run a small LAN at home masquarated with Linux using ip masquarading, and ip firewall. Although all machines on my network can access all information on the internet, only the machine which is doing the ip masquarading is available from the internet. In my last Apache article, I showed you how to recycle ip addresess, in this article I will demonstrates how to make a webserver behind a firewall available on the internet without changing rules on your firewall or compromising security. In this articel we will see how we can use Apache's ProxyPass directive to achive this goal. The target audience of this article is System Administrators or any one who is building a small to medium size LAN at home or at work.

ArticleIllustration:[This is the title picture for your article]

[Illustration]

ArticleBody:[The article body]

The problem with ip masquarding

For a long time on my LAN, the router (the machine that was doing that masquarating/firewall) was also acting as the web-server, mail-server, ftp-server, dns-server et all.
One day I had then the need to to serve web content from another machine that was behind the firewall.
I also wanted to serve some documents from an SGI IRIX box that was behind the network (a video server, serving streaming images). This machine had full access to the internet, but the internet users could not connect to the machine. Although I had no intentions to put this IRIX machine on the network, it was neccessary that people could connect to the web service that was available from this machine.

I was facing the same problem at work with a similar network and a Firewall.
Each time someone wanted a development webserver to be available from the internet for demo purpose, the rules on the firewall needed to be changed and you had to give the machine an external ip address and compromise the security of the network.

Apache to rescue: ProxyPass

After considering several solutions I implemented one with Apache and its ProxyPass directive.
ProxyPass require mod_proxy to be compiled in or loaded as a module with your Apache server.
Following is the definition of ProxyPass from Apache manual

ProxyPass

Syntax: ProxyPass <path> <url>
Default: None
Context: server config, virtual host
Override: Not applicable
Status: Base
Module: mod_proxy
Compatibility: ProxyPass is only available in Apache 1.1 and later.

This directive allows remote servers to be mapped into the space of the local server; the local server does not act as a proxy in the conventional sense, but appears to be a mirror of the remote server. <path> is the name of a local virtual path; <url> is a partial URL for the remote server.

Suppose the local server has address http://wibble.org/; then

   ProxyPass /mirror/foo/ http://foo.com/
will cause a local request for the <http://wibble.org/mirror/foo/bar> to be internally converted into a proxy request to <http://foo.com/bar>.

Real world example

Mapping the internal video server to the external web server.
Internal network: hometranet.home 192.168.1.0/255.255.255.0
(in the theme of internet, intranet, extranet, I call my home network hometranet)
External network: developer.ch 193.192.254.50

Video server (internal) running on host cam.hometranet.home serving
video streams from url http://cam.hometranet.home:5555/cams/sony/stream
and
still images from camera at http://cam.hometranet.home:5555/cams/sony/image
I wanted to view the result from those urls when I visit
http://mozilla.developer.ch/stream
and
http://mozilla.developer.ch/image
This can be easily done by using the ProxyPass directive from Apache by simply adding the following lines in the httpd.conf or srm.conf

ProxyPass /video http://cam.hometranet.home:5555/cams/sony/stream
ProxyPass /video http://cam.hometranet.home:5555/cams/sony/stream
Now after restarting the web server (if mod_proxy was available), http://mozilla.developer.ch/image answers from the cam webserver.
For the user visiting the site its totally transparent, and almost* no security was compromised by using this method.
*I used the word almost, because there is no such thing as total security on the internet :)

Mapping Virtual Servers

The proxypass trick can be used to map a virtual host entirely to a different machine.
For example:
docs.sun.developer.ch mapped to solsparc.hometranet.home

NameVirtualHost 193.192.254.50
<VirtualHost 193.192.254.50>
     ServerName sun.docs.developer.ch
     ProxyPass / http://solsparc.hometranet.home/
     TransferLog /net/www/logs/sun.docs.access
     ErrorLog    /net/www/logs/sun.docs.errror
</VirtualServer>
you can also forward to hosts by their ip address
<VirtualHost 193.192.254.50>
     ServerName sun.docs.developer.ch
     ProxyPass / http://192.168.1.7/
     TransferLog /net/www/logs/sun.docs.access
     ErrorLog    /net/www/logs/sun.docs.errror
</VirtualServer>

Caveats

Since your main web server is making requests to the internal web servers on behalf of your users, you cannot do any sensible logging on the target host, instead you have to log all requests on the source host.
In the above case I log entries on the main host sun.docs.developer.ch instead of solsparc.hometranet.home
Results of logging on sun.docs.developer.ch (dummy result)

197.0.22.3 - - [05/Nov/1999:22:09:04 +0100] "GET /index.html HTTP/1.0" 304 -
187.0.45.67 - - [05/Nov/1999:22:09:04 +0100] "GET /navi.html HTTP/1.0" 304 -
177.0.5.45 - - [05/Nov/1999:22:09:04 +0100] "GET /entrees.html HTTP/1.0" 304 -
227.0.9.67 - - [05/Nov/1999:22:09:15 +0100] "GET /complets.html HTTP/1.0" 304 -
137.0.7.23 - - [05/Nov/1999:22:09:19 +0100] "GET /menu_poisson.html HTTP/1.0" 200 841
193.192.245.73 - - [05/Nov/1999:22:09:25 +0100] "GET /volailles.html HTTP/1.0" 304 -
192.167.0.1 - - [05/Nov/1999:22:09:44 +0100] "GET /agneau.html HTTP/1.0" 304 -                                                            
Results from logging on solsparc.hometranet.home
192.168.1.1 - - [05/Nov/1999:22:09:04 +0100] "GET /index.html HTTP/1.0" 304 -
192.168.1.1 - - [05/Nov/1999:22:09:04 +0100] "GET /navi.html HTTP/1.0" 304 -
192.168.1.1 - - [05/Nov/1999:22:09:04 +0100] "GET /entrees.html HTTP/1.0" 304 -
192.168.1.1 - - [05/Nov/1999:22:09:15 +0100] "GET /complets.html HTTP/1.0" 304 -
192.168.1.1 - - [05/Nov/1999:22:09:19 +0100] "GET /menu_poisson.html HTTP/1.0" 200 841
192.168.1.1 - - [05/Nov/1999:22:09:25 +0100] "GET /volailles.html HTTP/1.0" 304 -
192.168.1.1 - - [05/Nov/1999:22:09:44 +0100] "GET /agneau.html HTTP/1.0" 304 -
192.168.1.1 - - [05/Nov/1999:22:09:56 +0100] "GET /desserts_ind.html HTTP/1.0" 304 -
192.168.1.1 - - [05/Nov/1999:22:10:00 +0100] "GET /cocktails.html HTTP/1.0" 304 -
192.168.1.1 - - [05/Nov/1999:22:10:10 +0100] "GET /cgi-bin/commande.cgi HTTP/1.0" 200 2146        

The same applies also to name based or ip bases ACLs (access control list).
If you want to block some hosts/ip addresses or give access to certain ip addresses to special area then this should be done on the main server (the one on remotely available) instead of the local server.
Further more you cannot restrict users based on Directory.
You can use Location or Files or FilesMatch directive though.
Following example touch some of them. Example:
<VirtualHost 193.192.254.50>
     ServerName sun.docs.developer.ch
     #this rule only allows users from good.host.com domain
     <Location /private>
          order deny,allow
          deny from all
          allow from good.host.com
     </Location>
     #This rule deny's the uncool Microsoft's monopoly helper browser.
     BrowserMatch MSIE uncool_browser
     <Location /coolpages>
         order allow,deny
         allow from all
         deny from env=uncool_browser
     </Location>
     #This rule only allows users that are in your passwd.httpd file
     <Location /coolpages>
         AuthName "only for registered users"
         AuthType Basic
         AuthUserFile "/etc/httpd/passwd.httpd"
         <Limit GET>
              require valid-user
         </Limit>
     </Location>

     ProxyPass / http://192.168.1.7/
     TransferLog /net/www/logs/sun.docs.access
     ErrorLog    /net/www/logs/sun.docs.errror
</VirtualServer>

Additional Resources

[Apache mod_proxy documentation]
http://www.apache.org/docs/mod/mod_proxy.html
[Apache name-based Virtual Host Support]
http://www.apache.org/docs/vhosts/name-based.html
[Apache Virtual Host documentation]
http://www.apache.org/docs/vhosts/index.html

mirror server hosted at Truenetwork, Russian Federation.