the djb way

publicfile


httpd, the publicfile web server

Like most services in the djb way, the publicfile servers we install rely on the daemontools and ucspi-tcp packages to operate.

Also like most other services, we will run the publicfile servers with non-priveleged user accounts. Many systems have accounts such as www and ftp already set up, and you may use them with publicfile if you want. In the examples that follow, though, we will designate a user account specific to each of the publicfile services. So you will notice user pubhttp for the http service, and user pubftp for the ftp service, each a member of group nofiles. User multilog will continue to be used for logging.

Once these preliminaries are in place, the only thing you need to decide is where you want to put the document archive in the filesystem. The directory conventions of publicfile don't quite match up to what you may be used to in the way of Apache's DocumentRoot or ftpd's ~ftp/pub. Work through this example, and then decide whatever.

In the setup that follows, we will segregate the document archives of the publicfile web server from the ftp server. The web archives in this example will be rooted in /var/public/http, so we make the following directories:

# umask 0022
# mkdir -p /var/public/http/0

What's that 0 (zero) directory for on the end? Some older HTTP clients (pre HTTP/1.1) do not use a hostname in their requests. For such clients, httpd uses 0 as a default host name, and looks in the 0 subdirectory to serve the requested file.

Otherwise, requests will be directed by hostname. This means that requests for files from host www.example.org will be served from the directory:

/var/public/http/www.example.org

If www.example.org is the default web URL for this server, --and, of course, if DNS resolves www.example.org to this server's IP address-- link this hostname to the default 0 directory:

# cd /var/public/http
# ln -s 0 www.example.org

Now all requests to the default server, with or without the hostname, will be served from the same directory. For testing and/or playing around before going on line, you may also want to add a link from localhost:

# ln -s 0 localhost

Then when you are working on the server itself, you can test it by browsing to http://localhost/. We may add additional subdirectories to /var/public/http for virtual hosts later on. For now, though, let's get the service up and running.

First, make the directories for defining the publicfile httpd service:

# mkdir -p /var/svc.d/publicfile-httpd/log

Copy this run script into /var/svc.d/publicfile-httpd/run:


#!/bin/sh
# publicfile-httpd/run
# daemontools run script for publicfile httpd service
#
CONLIMIT=101
HTTP_ARCHIVE="/var/public/http"

exec 2>&1
echo "*** Starting publicfile-httpd on ${HTTP_ARCHIVE}:"
exec envuidgid pubhttp softlimit -o25 -d250000 \
  tcpserver -vDRH -l0 -b50
  -c ${CONLIMIT} \
  0 80 \
   /usr/local/publicfile/bin/httpd ${HTTP_ARCHIVE}

Make it executable, chmod 755. Notice the use of envuidgid to setup the environmental variables $UID and $GID for user "pubhttp". We don't need to follow on with the -U option to tcpserver here, because the httpd executable itself drops priveleges to $UID/$GID.

Note also that the tcpserver invocation in this run script doesn't use any tcprules to restrict connections. The idea with publicfile is that you intend for your files to be, well, public. If you want to set up a server restricted to certain clients, use the -x switch to tcpserver, specifying rules in /etc/tcprules as usual.

Next copy this run script into /var/svc.d/publicfile-httpd/log/run for the logging service:


#!/bin/sh
# publicfile-httpd/log/run
# daemontools run script for publicfile httpd logger
#
exec setuidgid multilog multilog t /var/multilog/httpd 

Set executable with chmod 755. Create the usual directory for multilog:

# mkdir -p /var/multilog/httpd
# chown multilog /var/multilog/httpd

Activate the httpd service now, by linking into /service:

# ln -s /var/svc.d/publicfile-httpd /service/httpd

Put some test page named index.html in /var/public/http/0/index.html and point your browser at http://www.example.org/. Your page should pop up. If not, go through the usual trouble-shooting procedures, make sure the run scripts are executable, that multilog owns the log directory, and that the softlimit parameters aren't too tight.

When the server is serving, you can populate the directory /var/public/http/0 with the documents for your site. The files you intend to serve must at least have permissions of 444 (usually 644), that is, readable by everyone. Also, any directories within the archive must at least have permissions of 555 (usually 755). That is, all directories must have execute bits (also known as the "search" bits) set for everyone.

publicfile ignores files beginning with a dot. Also, publicfile will not serve files set to mode 645 (-rw-r--r-x). That is, if the execute bit is set for "other", but not set for "user", publicfile will turn a blind eye to the file. This feature is intended to let users mark files as hidden from publicfile, while still letting the file be readable by other users on the host.

What about your users? At many sites, Paula may want to put documents in her own directory in ~/public_http that are accessible over the Internet via the convention:

http://www.example.org/~paula/

To handle this, create a subdirectory for Paula within /var/public/http/www.example.org/, with a symbolic link back to her home directory:

# mkdir /var/public/http/www.example.org/\~paula
# chown paula:group /var/public/http/www.example.org/\~paula
# ln -s /var/public/http/www.example.org/\~paula /home/paula/public_html

(In the above example, we assume Paula's ~/public_html is created for the first time. If it already exists, move it out of the way, make the link, then copy the contents back into the new ~/public_html link.)

The symbolic link we made for Paula may seem to be in the opposite direction you might have first expected. Note that all files served by publicfile must physically reside within its archive. This is because publicfile chroots to the directory specified in the argument to the invocation of httpd. It can't see any files outside of this path.

You can create any number of named virtual hosts for your server, easy as pie:

# cd /var/public/http
# mkdir www.example.com
# mkdir www.example.edu
# mkdir www.example.info
...

This example shows the same server hosting sites for the example.com and example.edu domains, etc. Each directory will have the contents served for that site. Just create the directory and populate it, no need to restart httpd for the new site to take effect. (Again, of course, DNS records must first be present to resolve each site's name to this server's IP address.)

When hosting virtual domains, you may prefer using the 0 default hostname directory only to serve a simple message regretting the lack of support for older browsers, while setting up the www.example.org directory separately with the material just for that site. In this way, clients with old browsers won't inadvertently get documents from the default archive when they are seeking material from a virtual host.

Alternatively, screw the losers with their older browsers, and do away with the 0 directory nonsense entirely.

Maybe you want an intranet:

# mkdir /var/public/http/staff.example.org

It's fine, as long as you remember again that publicfile is public. There's no logging in, no authentication, no other forms of access restriction. If the documents on your intranet aren't intended to be world readable, put this web server up on an internal network with a private IP address instead, possibly in conjunction with a virtual private network (VPN) for your remote users.

Note that publicfile can also handle IP-based virtual hosts. To do this, though, create separate instances of httpd (separate service directories, run scripts, etc.), each binding to a specific IP address by way of its tcpserver invocation. (Or use your router/packet filter to redirect traffic by IP address to the separate instances of httpd, each possibly running on the same IP address, but listening on different ports.)

Of course, setting up more than a few IP-based instances of httpd would soon become tiresome. Somebody has probably already developed a simple proxy/wrapper utility, that redirects incoming IP-based requests to a single httpd instance using name-based virtual hosts. (Worth further research?)


Copyright © 2002, 2003, 2004, Wayne Marshall.
All rights reserved.

Last edit 2004.10.04, wcm.