WebDeveloper.com �: Where Web Developers and Designers Learn How to Build Web Sites, Program in Java and JavaScript, and More!   
Web Developer Resource Directory WebDev Jobs
Animated GIFs
CSS
CSS Properties
Database
Design
Flash
HTML
HTML 4.01 Tags
JavaScript
.NET
PHP
Reference
Security
Site Management
Video
XML/RSS
WD Forums
 Client-Side
  Development

    HTML
    XML
    CSS
    Graphics
    JavaScript
    ASP
    Multimedia
    Web Video
    Accessibility
    Dreamweaver
    General
    Accessibility
    Dreamweaver
    Expression Web

    General

 Server-Side
  Development

    PHP
    Perl
    .NET
    Forum, Blog, Wiki & CMS
    SQL
    Java
    Others

 Site Management
    Domain Names
    Search Engines
    Website Reviews

 Web Development
  Business Issues

    Business Matters

 Etc.
    The Coffee Lounge
    Computer Issues
    Feedback




Many Servers, One Machine
Multi-Homing can be simple when you know the tricks

by Glenn Fleishman

Since the dawn of time (a year ago last summer), the question has constantly been asked: "How do I run multiple Web servers for separate domain names on the same machine?" The answer is a set of procedures to follow to make this happen, plus a free and major hack.

The reason for this question is obvious: it's cheaper to set up a beefy workstation or two with tons of storage, and then sell space off it, than it is to set up an individual workstation for each client. Most clients these days demand better than "http://www.isp.com/abc"; it's "http:// www.abc.com" or see you later.

And they're right to demand it--the difficulties in setting this up are technical but not impossible. It requires some knowledge of compiling C code, and tweaking of root-access files, but the rewards are immense. Commercial servers for Unix systems generally support this out of the box now, without any modification.

The examples here are generally cited for the CERN 3.0 httpd which is available in source code, and which is fully public-domain--all intellectual property rights have been given up by CERN for the code. Because of this, you'll find two interesting phenomena: first, that some companies will sell you a hacked CERN httpd for real dollars; second, that SPRY has released a $600 secure server based on the CERN code. They built the SSL and SHTTP modules and didn't have to develop a server from scratch like OpenMarket or Netscape Communications, which sell their secure servers for about $5,000 (plus a mandatory $1,000 per year for support).

Much of the talk about setting up ARP, running restart scripts, and fixing domain records will apply to any kind of server, not just httpd or the CERN httpd. You should note the combination of crontab and process monitor to make sure that if your httpds die in the middle of the night, your machine is "aware" and able to deal with it.

The Basics

Before we get down and dirty, let's define terms. First, you can really do this only on a Unix system, although I'm sure Windows NT and other OS hackers have ideas about how to accomplish this. As far as I know, it's currently impossible to do this on a Macintosh or a Windows 3.1 or Windows 95 machine, but later in the article, there will be some tips on using a little Unix to make this work, too (the just-released Apple Open Transport Protocol supports multiple separate interface addresses on a single machine, but vendors have to adopt and implement new code to make it possible).

What you're going to do is set up multiple IP (Internet Protocol) addresses, each of which will be a top-level Web site domain name, such as "www.phlegm.com." You may know that domain names and IP addresses are independent: You can assign multiple domain names to the same address, or you can assign multiple IP addresses to the same domain name (multi-homing).

You'll be "multi-homing" the machine you're running the Web servers on; each address will have a separate domain name, which points discretely to it. The point of this exercise is that domain name resolvers don't care what the domain name is; they resolve the name to an IP address and use that exclusively. So we have to make each running server listen to a single IP address, and make several IP addresses appear on a single machine.

Who Can Accomplish This

To make these changes, you'll either have to have root access to the Unix box you're working on, or be best pals with the system administrator who's responsible for the administration. Many of the changes involve somewhat low-level work, including changing the ARP tables and DNS records. If you don't run your own DNS, you'll have to arrange all this with your service provider or other group providing the work. Hopefully, before you begin this, you'll have a range of IP addresses already available for use, too.

Although most of the discussion here is about getting Web servers on two second-level domain names (like "www.xyz.com" and "www.abc.com") the techniques work absolutely identically for sub-domains inside a main domain. So you could set up separate servers for "macintosh-products.frogstar.com" and "windows-products.frogstar.com."

You'll also need to know something about compiling software under Unix, because both the NCSA and CERN flavors of modifications require you to tweak Makefiles and config.h files and then compile on the target platform. This can be very easy, if everything on your server is up to date and installed properly; and an endless task if it's not.

Fixing the Server

There are two key difficulties that must be overcome. First, the two major freeware Web servers, NCSA and CERN, are not set up to listen only to a specific IP address, but to respond to all traffic on a given port (default is port 80). Many of the commercial programs, such as NetSite from Netscape, can run multiple servers each homed to a specific IP number; on the other hand, NetSite starts at $1,495 for the non-encrypted version.

NCSA has been widely patched and updated. Refer to http://www.thesphere.com/~dlp/TwoServers for instructions on how to modify the source or acquire a modified version. You can also buy a commercially modified one. For unknown reasons, no one's yet documented the modifications you need to make to the more robust CERN code, so we're opening the floodgates and letting it out.

You'll find here the necessary distribution for compiling your own CERN daemon that supports multiple hosts. For many systems, you'll just need to retrieve the file, uncompress, extract with tar, modify the Makefile and other files per CERN's instructions for the regular daemon, and then do the appropriate make. This has been tested and runs successfully under SunOS 4.1.x, but we don't offer technical support for it, though we welcome suggestions for improving or porting (if that's even needed).

Configuration

After installing the binary, you'll be able to specify a new configuration file directive. The CERN daemon uses several dozen directives to control behavior of the daemon; this includes definitions of what directories contain executables for Common Gateway Interface (CGI) links or items as simple as the name of the log file. We've added a critical one to keep backwards compatibility of your old directories if you're migrating from an existing Web site to this.

The configuration file is usually located in a home directory, such as /usr/local/cern_httpd in the config directory. If you've just installed from scratch, you'll find a model file called all.conf that might be the most appropriate. In future issues, there will be more tips and articles on customizing this file.

Somewhere in the top of the file, probably at the end of the basic directives, before the redirects and so forth, you can add a line for the PathHead directive:

PathHead	/foobar
The idea behind PathHead is to allow you to take an existing subdirectory from an existing Web site and fold it into a specific-host Web site. Often, multiple Web sites using the generic-host CERN or another http daemon are set up by pointing all the domains to the same host IP address. So you would have "www.foobar.com" and "www.semperfi.com" pointing to 192.57.63.4. On that host, you would probably have two directories under the main Web directory, such as /foobar/ and /semperfi/. When you gave out the URL, the two sites would look like

http://www.foobar.com/foobar/
http://www.semperfi.com/semperfi/
They would actually point to the same machine and the same Web daemon, though; if your main Web directory was /usr/local/www, they would point, respectively, to
/usr/local/www/foobar/
/usr/local/www/semperfi/
This is the crux of what we're trying to entirely avoid with this modified daemon. But we don't want to have to rewrite all the paths--if you use absolute links--or move everything. So instead of that, you use the PathHead directive to tell the specific-host CERN daemon to point both
http://www.foobar.com/foobar/welcome.html
and
http://www.foobar.com/welcome.html
to the same directory. You'll need to link back in cgi-bin and other directories you might use across multiple daemons by making a symbolic link in your new root directory. If you've gotten to this point, you probably know how to do this, but (under SunOS 4.1.x):
cd /usr/local/www
ln -s cgi-bin foobar/cgi-bin

Domain Name Changes

First, map out servers you'll want to run separately. Each server should be assigned its own domain name (usually in the model "www.name.com", but it certainly doesn't have to be) and its own IP address. For the purposes of this example, let's say we have "www.foobar.com" at 192.0.0.1 and "www.snafu.com" at 192.0.0.2.

In the DNS records, you'll make some simple additions. To the db.foobar file (or whatever you've called the DNS record for the Foobar Corp.), add

www IN A 192.0.0.1
and to db.snafu
www IN A 192.0.0.2
Remember that you should always be a good Netizen and add the following to your reverse name records as well (in this case, db.192.0.0):
1 IN PTR www.foobar.com.
2 IN PTR www.snafu.com.
Restart the nameserver (kill -HUP is enough). In each configuration file (see above), you'll change the HostName directive line for each file to the exact domain name you specified here.

Next, you'll need to add alias or virtual interfaces and Address Resolution Protocol entries for each of the new addresses. Here's where it gets a little tricky.

Under System V, Linux, and other Unix implementations newer than BSD4.3, you can use a variation of the ifconfig statement (it can vary from system to system). The statement for each address would be in the form

ifconfig <interface> <ipaddr> alias
So using a Silicon Graphics running Irix, you might do the following:
ifconfig ec0 192.0.0.1 alias
Older Unix systems don't support this statement, but if you're running SunOS 4.x, you can use a simple piece of software called VIF (virtual interface), released for free by some kind souls. It uses the "modload" system that PPP code depends on; the modload allows the creation of fake interfaces.

The code is available here and requires very few changes. Read through the Makefile and the README. Make localization changes and do just "make". If it compiles without errors, do "make install" and it will create a device file, do the modload, install the interfaces, and do a "netstat -ian" to show the installed interfaces.

A noticeable improvement in the original code is to change the #DEFINE NVIF statement. The default is 4; you can change it to almost any number. I have successfully installed 64 interfaces with no apparent problems. After changing this number, use "modstat" to get the vif module number, then "modunload -id #" to remove the vif module; recompile and reinstall. Note: you must modunload before doing install, or you will likely hard-crash the machine.

One difficulty in assigning interfaces is that the SunOS can't properly display that many interfaces because of a limitation in its numbering. If you do "netstat -ian", it starts using ASCII characters, because the original ifconfig didn't think about more than 10 interfaces! (It's obviously incrementing an ASCII value rather than converting a counter into ASCII numbers.) However, ifconfig is smarter, and "ifconfig -a" will provide you the actual numbers of the interfaces. If you allot too many, however, it will drop some of them out. There's no good answer here to have your cake and/or eat it.

With VIF installed, you can then specify the IP addresses by using

ifconfig <vif#> <ipaddr>
just like you would to define an interface address. Next, you'll need to add ARP entries. These entries will allow remote devices to find your new IP addresses by using the MAC number of the interface they're aliased or vif'd to. You'll need to get the MAC number of your Ethernet interface by doing "ifconfig <interface>". This will return the MAC sextet, which will look like "8:0:20:c:24:64". (All MAC addresses are unique, like IP numbers.) To add an IP address to the ARP table, use the command under SunOS 4.x (do "man arp" on other systems to get the exact nomenclature):
arp -s <ipaddr> <MACaddr> pub
If you make a mistake, you'll have to use "arp -d <ipaddr>" to remove the entry and then add it again.

Note that VIF and the ARP changes--and often the ifconfig . . . alias changes--will not show up if the machine is rebooted. You'll need to make appropriate changes to your rc files. I'm going to provide the examples and programs need to do this under SunOS 4.1.3; mileage on other systems, especially those with highly complex init.d and rc files, will vary.

In the /etc/rc.local file, at the end, add this code :

if [ -f /usr/construction/vif/vif_exec ]; then
modload -entry _vif_vdcmd -exec /usr/etc/vif/vif_exec \
/usr/etc/vif/vif.o
/usr/local/bin/perl /usr/etc/viflist
fi
Change /usr/etc/vif to the whatever path you installed VIF under. Now the viflist program is a straightforward hack I wrote in Perl for simplicity's sake. Drop your MAC address for the machine into $mac.
#!/usr/bin/perl
$mac = "8:0:20:c:54:3a";
$i=0;
open (VIF, "< /etc/viflist.addr");
while (<VIF>) {
        chop;
if (/^\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}$/) {
                system("ifconfig vif$i $_");
                system("arp -s $_ $mac pub");
                $i++;
        }
}
You then need to create a file at /etc/viflist.addr which contains a list of IP addresses you want installed at system reboot. Whenever you add a new address, you should make sure and add that address to this list.

Configuring and Launching

If you're running just a single CERN httpd or an unmodified one, it's fairly easy to get it running (other systems are similar or easier). You type in the following at a command line--and add it to the appropriate rc file:

<path-to-daemon>/httpd -r <path-to-config-file>/<config file>
With multiple, individually addressed httpds, you'll need to enter this item for each separate config file and add it to the rc file. Or, you can run a simple script that automatically accounts for new configuration files. This script checks a directory for all files beginning with www (name all your configuration files that way) and compares it against running httpds. If it can't find one named with that configuration file, it starts it and logs the fact that it had to restart it.

This is necessary especially under systems that are a little overloaded (or a lot), as occasionally an httpd will fail to spawn a child process, or die, or the process table will run out of entries, and your daemon will disappear.

This program (called launchall) should be added to the rc file as above, and it should also be added to the crontab for root, so that it runs every 15 or 30 minutes. This assures you that even if your daemons die or the machine does a restart, the daemons will be up and running with 15 minutes (or whatever time you set).

#!/usr/bin/perl
require 'ctime.pl';
opendir(DIR, "/usr/local/cern_httpd/config/");
@wwws = grep(/^www/,readdir(DIR));
close DIR;
open(PS, "ps wwax | grep cern | grep -v grep|");
@ps = <PS>;
close PS;

foreach (@ps) {
        chop;
        s/.*\/usr\/local\/cern_httpd\/config\/(.*)/\1/;
}

open(LOG, ">>/usr/local/cern_httpd/config/loglaunch");

foreach (@wwws) {
        $match = 0;
        $www = $_;
        foreach (@ps) { if ($www =~ /$_/) { $match = 1; } }
        if (!$match) {
   system("/usr/local/cern_httpd/bin/httpd -r\ 
/usr/cern_httpd/config/$www");
                print "Restarted $_ at " . &ctime(time);
                print LOG "Restarted $_ at " . &ctime(time);
        }
}
close LOG;
if (-e "/usr/cern_httpd/core") { unlink "/usr/cern_httpd/core"; }

If you'd rather be notified about httpd failures than have them logged, replace the "print LOG" line with:
open (MAIL, "|/usr/ucb/mail -s \"Restarted $_\" email@blah.com");
print MAIL "Restarted $_ at " . &ctime(time);
close MAIL;
Root will automatically get mail whenever launchall restarts a daemon, because it always wants to write to standard output, and, if it can't, dumps to root mail. Add the below to your appropriate rc file (when it runs at startup, it'll dump out to standard output the daemons that have been restarted):
if [ -f <path-to-launchall>/launchall ]; then
<path-to-launchall>/launchall
fi

Clean-Up and Practical Concerns

Using this approach will create a number of simultaneous httpds running--one for each of the separate IP addresses you set up, so make sure you have enough memory and enough room in the process table to handle it.

If you're running SunOS 4.x, make sure you have at least 32 MB of RAM on the machine you're running five or six of these httpds on (I've successfully handled a 210,000-hit day with a single Sun Sparc with 32 MB and these modifications).

Other details to think about are modifying the log file directives to create separate logs and error files for separately running daemons. You can keep all log entries being fed into the same file, or not, as you choose.

Coolness

I'm giving away one of my company's biggest "secrets" in this piece, but to quote the Internet saying of last year (haven't heard it much this year), "information wants to be free." Improving the use of free software--and making better use of commercial software--advances the entire industry, and should be promoted.

If you have tips like this, no matter how detailed, please drop a note to me via e-mail. I can't offer technical support--nor can Web Developer�--for the above code, but we'll try to answer frequently asked questions in the Web site for the magazine.


Reprinted from Web Developer� magazine, Vol. 1 No.1 Winter 1996 (c) 1996. All rights reserved.




HTML5 Development Center


Recent Articles