From the Mind of Eric Lalonde

A Dumping Ground of Technical Information

First Thoughts on the New OpenBSD httpd Webserver

In OpenBSD 5.6, apache has been removed from base entirely, and the community has been advised that nginx will be removed from base in 5.7. In their place, a home-grown webserver, named simply httpd, is now available in the OpenBSD 5.6 base system. The man page provides a brief overview:

 HTTPD(8)                OpenBSD System Manager's Manual               HTTPD(8)     

 NAME     
      httpd - HTTP daemon     

 SYNOPSIS     
      httpd [-dnv] [-D macro=value] [-f config_file]     

 DESCRIPTION     
      The httpd daemon is a HTTP server with FastCGI and SSL support.

      The FastCGI implementation has optional socket support.  httpd can log to
      syslog or per-server files with several standard formats.

      httpd rereads its configuration file when it receives SIGHUP and reopens
      log files when it receives SIGUSR1.

OpenBSD’s httpd has some nice features that caught my attention:

  1. Proper privilege separation - after binding to the http port, the server runs as the lesser-privileged user named www.
  2. Use of chroot to limit the harm that an attacker can do should the server be compromised.
  3. Simple and straightforward configuration file format.

If you’re like me, and you need only to serve up static content, then migrating your website to httpd is a simple matter. The /etc/examples directory contains sample implementations of various services on an OpenBSD system. Not surprisingly, the file we’re interested in is /etc/examples/httpd.conf.

1
# cp /etc/examples/httpd.conf /etc

The file contains a number of examples. For my configuration, I kept only the example that demonstrated a name-based virtual server (In OpenBSD 5.6, this example starts on line 22). All other examples were removed. Next, I replaced ‘example.com’ with the appropriate domain name. The result is the following:

1
2
3
4
5
6
7
8
9
# cat /etc/httpd.conf
ext_addr="egress"

# A name-based "virtual" server on the same address
server "www.protoc.org" {
        listen on $ext_addr port 80

        root "/htdocs/www.protoc.org"
}

It’s important to remember that httpd runs in a chroot. If you don’t know what this means, it’s important to use your google skills to find out before continuing. As the man page states, the default target of the chroot is /var/www. So, in reality, /htdocs directory mentioned above on line 8, is in fact /var/www/htdocs.

Other httpd configuration settings are discussed further in the man page.

Dynamic Content Hosting

But what if you’re not like me, and you need to host both static and dynamic content? The good news for you is that httpd comes with FastCGI support. What is FastCGI?

 FastCGI is a binary protocol for interfacing interactive programs with a web server.
 FastCGI is a variation on the earlier Common Gateway Interface (CGI); FastCGI's main
 aim is to reduce the overhead associated with interfacing the web server and CGI programs,
 allowing a server to handle more web page requests at once.

In order to get your dynamic content loaded into httpd, you’ll need a FastCGI interface to your content. This need is fufilled by an service called slowcgi which speaks the FastCGI protocol.

The exact instructions for loading dynamic content into httpd is use-case dependent, obviously. Below I have outlined a few of the important steps that you can adapt to your situation. The examples below assume we want to allow httpd to invoke perl scripts to perform some action.

  • First thing’s first: Get your script working under your chroot environment.

Do this first. It is important to isolate issues related to your chroot before httpd is even in the picture. This approach makes it easy to isolate issues with your chroot setup from issues with your httpd configuration, or from issues with your httpd <-> slowcgi interaction. Here’s an example script run under chroot:

1
2
3
4
5
6
$ cat /var/www/bin/test.pl
#!/usr/bin/perl
print "Hello!"

# chroot -u www /var/www /bin/test.pl
Hello!

If the above command doesn’t work, then I know perl isn’t installed correctly under chroot. Installing a program (and dependencies) into a chroot is a topic unto itself, and certainly beyond the scope of this blog entry, but it usually starts with something like:

1
2
3
4
5
6
7
8
9
10
$ ldd /usr/bin/perl
/usr/bin/perl:
        Start            End              Type Open Ref GrpRef Name
        000019f2f3d00000 000019f2f4102000 exe  1    0   0      /usr/bin/perl
        000019f575663000 000019f575a75000 rlib 0    2   0      /usr/lib/libpthread.so.18.0
        000019f5ba126000 000019f5ba6a0000 rlib 0    1   0      /usr/lib/libperl.so.15.0
        000019f5dce8c000 000019f5dd2b4000 rlib 0    1   0      /usr/lib/libm.so.9.0
        000019f5852a6000 000019f5856b2000 rlib 0    1   0      /usr/lib/libutil.so.12.1
        000019f5a91bb000 000019f5a96a4000 rlib 0    1   0      /usr/lib/libc.so.77.0
        000019f50af00000 000019f50af00000 rtld 0    1   0      /usr/libexec/ld.so

Perl will expect all of those libraries to exist, and has no idea it is being invoked under a chroot. All of the above files need to be installed in to the chroot destination in order to satisfy perl’s dependencies. Knowing the full extent of dependencies of a chrooted application is often an exercise in trial and error. Google is your friend here.

  • Update httpd.conf

Now that we know the interpreter works, we can move on to updating httpd.conf with FastCGI support:

1
2
3
4
5
6
7
8
9
10
11
12
13
$ cat /etc/httpd.conf
ext_addr="egress"

server "default" {
       listen on $ext_addr port 80

       location "/cgi-bin/*" {
               fastcgi

               # The /cgi-bin directory is outside of the document root
               root "/"
       }
}

The above configuration has been simplified to focus entirely on FastCGI configuration. The changes are straightforward given what we are trying to achieve.

  • Enable slowcgi server
1
2
# vi /etc/rc.d.conf.local
slowcgi=""

Add the above line to inform OpenBSD to start slowcgi at boot.

With slowcgi running, and the chroot correctly configured, httpd should be able to invoke the script. Loading the script in a webpage should generate the expected output.

Debugging

Keep in mind that both httpd and slowcgi can be run in the foreground, from the command line, with the -d option. This is particularly useful since httpd will log directly to the console. If you’re really stuck, open two terminals on your webserver: one running slowcgi, one running httpd, both in the foreground. Any issues concerning interactions of these two services should become obvious quickly.

Other Notes

This guide is meant only as an introduction to httpd. Deploying your content safely and securely is the responsibility of the adminstrator. Many important concepts were not covered, such as file permissions and common security mistakes people make when deploying applications inside a chroot. For those new to web hosting, an in-depth understanding of these issues may save you from some embarassing results.

Also note that httpd was only introduced to base in OpenBSD 5.6. The stated goal of the authors is to get people testing it now before widespread deployment. Hopefully this guide helps you do so.