10.5 Serving Web Content Through HTTP

One of the biggest trends in network-enabling embedded systems is the inclusion of a web (HTTP) server. The added HTTP server can then be used for enabling remote administration or remote data viewing. In the case of my SYSM module, for example, the HTTP server enables my users to configure and monitor various aspects of the control system.

Though the open source Apache HTTP server is the most widely used HTTP server in the world, it is not necessarily fit for embedded systems. Mainly, it is very difficult to cross-compile and tends to be rather large in terms of required storage space. There are, nevertheless, other open source HTTP servers that are much more adapted to embedded systems. In particular, Boa and thttpd are small, lightweight, fast servers and are a perfect fit for embedded Linux systems.

There does not seem to be a clear set of characteristics to help in choosing between Boa and thttpd. The only really notable difference is that Boa is distributed under the terms of the GPL while thttpd is distributed under the terms of a BSD-like license. The size of the resulting binaries are, however, quite comparable. Both packages also support CGI scripting. Therefore, I suggest you have a look at both to decide which one you prefer.

10.5.1 Boa

Boa is available from http://www.boa.org/ and is distributed under the terms of the GPL. Boa requires only a C library and can be compiled both against glibc and uClibc. For my SYSM module, I used Boa 0.94.13.

Download and extract Boa in your ${PRJROOT}/sysapps directory. With the package extracted, move to the appropriate directory:

$ cd ${PRJROOT}/sysapps/boa-0.94.13/src

Configure and compile Boa:

$ ac_cv_func_setvbuf_reversed=no CC=arm-linux-gcc ./configure \
> --host=$TARGET
$ make

The command line above generates a dynamically linked binary. If you would rather have a statically linked binary when compiling with uClibc, add LDFLAGS="-static" to the make command line. To statically link against glibc, use the following make command line instead:

$ make \
> LDFLAGS="-static -Wl --start-group -lc -lnss_files -lnss_dns \
> -lresolv -Wl --end-group"

If you are trying to statically link Boa against glibc but you didn't use the - -enable-static-nss option when configuring the build of the library, the command line above will fail because of missing files.

If you try to avoid this error by using only LDFLAGS="-static" with a glibc not built for enabling static NSS linking, the resulting binary will not function properly on the target, as I said in Chapter 4. Mainly, the binary attempts to load its dynamic NSS libraries from ${TARGET_PREFIX} on the target. Since this directory doesn't exist, Boa always fails to find the libraries it needs and stops. Though it may complain about a different sort of problem, such as an unknown user, you can see the files it tries to open using strace.

To avoid these problems altogether, you must recompile glibc with the - -enable-static-nss option. Once the library is recompiled and installed, you will be able to link a real static binary that includes the appropriate NSS libraries.

Note that you won't encounter this type of problem with uClibc, since it doesn't implement glibc-style NSS.

The compilation time is short. When linked against uClibc and stripped, the resulting binary is 60 KB in size when linked dynamically and 90 KB when linked statically. When linked against glibc and stripped, the resulting binary is 60 KB in size when linked dynamically and 520 KB when linked statically.

Once the binary is ready, copy it to your target's root filesystem and strip it:

$ cp boa ${PRJROOT}/rootfs/usr/sbin
$ arm-linux-strip ${PRJROOT}/rootfs/usr/sbin/boa

For Boa to run, it needs a boa/ subdirectory in the target's /etc directory and a configuration file in that same directory. Create Boa's directory and copy the sample configuration file to it:

$ mkdir -p ${PRJROOT}/rootfs/etc/boa
$ cp ../boa.conf ${PRJROOT}/rootfs/etc/boa

At runtime, Boa will need a user account to run. This user account is specified in the boa.conf file. Edit this file and your target's /etc/passwd and /etc/groups files to add a user for Boa to use. Boa also needs a /var/log/boa directory on your target's root filesystem to log accesses and errors:

$ mkdir -p ${PRJROOT}/rootfs/var/log/boa

Remember that log files can be a problem in an embedded system if their growth is not restricted. Having a script that runs periodically to reinitialize such files, for example, is a simple way to ensure they don't use up the available storage space.

When running, Boa finds its web content from the target's /var/www directory. This is where you should put any HTML files, including index.html. Create the directory and copy your content to it:

$ mkdir -p ${PRJROOT}/rootfs/var/www 
$ cp   ... ${PRJROOT}/rootfs/var/www 

Finally, add a line in your target's /etc/inittab for Boa. On my SYSM module, for example, here is the line I add for Boa:

::respawn:/usr/sbin/boa

For more information on how to use Boa, see the documentation included in the Boa package and on the project's web site.

10.5.2 thttpd

thttpd is available from http://www.acme.com/software/thttpd/ and is distributed under a BSD-like license. In addition to the C library, thttpd also depends on the cryptography library (libcrypt). Download and extract thttpd in your ${PRJROOT}/sysapps directory. For my SYSM module, for example, I used thttpd 2.23beta1. Move to the package's directory for the rest of the instructions:

$ cd ${PRJROOT}/sysapps/thttpd-2.23beta1

Now, configure and compile thttpd:

$ CC=arm-linux-gcc ./configure --host=$TARGET
$ make

This command line generates a dynamically linked binary. As with Boa, to generate a statically linked binary with uClibc, add LDFLAGS="-static" to the make command line. To statically link against glibc, you must use a make command similar to that used for Boa:

$ make \
> LIBS="-static -Wl --start-group -lc -lnss_files -lnss_dns \
> -lcrypt -lresolv -Wl --end-group"

As with Boa, if you are trying to statically link thttpd against a version of glibc that wasn't built to enable static NSS linking, the command line above will fail. Even if bypassed using LDFLAGS="-static", the resulting binary will not function properly on the target. See the note in the previous section for details.

As with Boa, the compilation ends quickly. When linked against uClibc and stripped, the resulting binary is 70 KB in size when linked dynamically and 115 KB when linked statically. When linked against glibc and stripped, the resulting binary is 70 KB when linked dynamically and 550 KB when linked statically.

Copy the resulting binary to the target's root filesystem and strip it:

$ cp thttpd ${PRJROOT}/rootfs/usr/sbin
$ arm-linux-strip ${PRJROOT}/rootfs/usr/sbin/thttpd

Unlike Boa, you can configure thttpd either by using a configuration file or by passing the appropriate command-line options. Use the -C option to provide a configuration file to thttpd. An example configuration file is provided in contrib/redhat-rpm/thttpd.conf. If you wish to use a configuration file, edit this file to fit your target's configuration after having copied it to your target's root filesystem:

$ cp contrib/redhat-rpm/thttpd.conf ${PRJROOT}/rootfs/etc

Like Boa, thttpd operates with a special user account. By default, it uses the nobody account. Create this account using procedures outlined earlier, or set thttpd to use an account of your choice. The configuration file copied earlier specifies the use of the httpd user. It also identifies the target's /home/httpd/html directory as the location for source HTML files:

$ mkdir -p ${PRJROOT}/rootfs/home/httpd/html

Finally, edit your target's /etc/inittab file. Here is the line I add for thttpd in my SYSM module's inittab:

::respawn:/usr/sbin/thttpd -C /etc/thttpd.conf

For more information on how to install and run thttpd, see the manpage included in the package and the project's web site.

10.5.3 A Word on Apache

Apache is available from http://www.apache.org/ and is distributed under the Apache license.[6] As I said earlier, Apache does not lend itself well to cross-compiling. If you are not deterred by this warning and would still be interested in attempting to cross-compile Apache, have a look at the procedure outlined by David McCreedy in his posting to the Apache development mailing list: http://hypermail.linklord.com/new-httpd/2000/May/0175.html. If you succeed, you'll probably want to take peek at Apache: The Definitive Guide by Ben Laurie and Peter Laurie (O'Reilly) for more information regarding the configuration and use of Apache.

[6] This license is BSD-like. See the LICENSE file included with the package for the complete licensing details.