Installing rc-httpd on OpenBSD

Last updated: 2016-12-21T21:13:57-0500

Rc-httpd is a shell script that serves the requested file or an index of files found under a website's root directory, or, in the case of CGI, executes a specified CGI program. Compact, simple, works. It was written on OS X (of all things) but works fine on any system that can execute the rc shell. For example, rc-httpd now ships with the 9front fork of Plan 9 from Bell Labs. In fact, it serves the 9front.org and cat-v.org websites, as well as the page you are reading right now.

How this setup will work

Daemontools will run as root and ensure that the network listener listen1(8) continuously answers network queries on port 80. The listener will then run the setuidgid program from daemontools to become user _rc-httpd and pass the open file descriptors along to the shell script tcp80, which in turn will execute rc-httpd (and in our case, execute werc) which will display a simple website.

Optionally, the ucspi-tools tlss(1) program can be used in a pipeline to negotiate TLS connections, passing along its file descriptors to the shell script tcp443, which in turn will execute rc-httpd (and in our case, werc). If you don't need to serve TLS, the related steps can be safely omitted.

Note: Throughout this document, you will need to change all references to domain.com to the hostname of your site. You will also need to change all references to user to the correct username on your system.

Prerequisites

Rc-httpd's sole prerequisite is some form of the rc shell, which is most conveniently found bundled with some version or derivative of Plan 9 from User Space.

Note: Many UNIX systems package a stand alone clone of rc written by Byron Rakitzis. It was originally created based on the rc paper by Tom Duff, and includes several incompatible changes to its syntax. Byron's rc is incompatible with rc-httpd and werc.

Begin by installing a compatible rc:

pkg_add plan9port	# or your choice of p9p forks
cp /usr/local/plan9/bin/rc /bin/	# to simplify bang paths
cp /usr/local/plan9/bin/awk /bin/	# ""

rc-httpd comes with werc

Werc is a minimalist web anti-framework built following the Unix and Plan 9 tool philosophy of software design. It is likewise a shell script. Rc-httpd is included with werc as a proof-of-concept web server.

It is wise to install werc (and therefore, rc-httpd) as a non-root user:

# as user
mkdir $HOME/www
cd $HOME/www
hg clone https://code.9front.org/hg/werc

But we'll still run rc-httpd from a dedicated user account:

groupadd _rc-httpd
useradd -g _rc-httpd -d /home/user/www/werc/bin/contrib/rc-httpd _rc-httpd

daemontools

The rc-httpd shell script can be launched and managed with daemontools:

cd /root/src
wget http://openbsd.stanleylieber.com/src/daemontools-0.76.tar.gz
tar zxvf daemontools-0.76.tar.gz
cd admin/
wget http://openbsd.stanleylieber.com/src/daemontools-0.76.errno.patch
cd daemontools-0.76
patch -p1 <../daemontools-0.76.errno.patch
package/install
mkdir -p /supervise/rc-httpd
>/supervise/rc-httpd/run
chmod 775 /supervise/rc-httpd/run
ed /supervise/rc-httpd/run
i
#!/bin/sh
exec /usr/local/plan9/bin/listen1 tcp!domain.com!80 \
	/usr/local/bin/setuidgid _rc-httpd \
	/home/user/www/werc/bin/contrib/tcp80
.
w
q
# for TLS
mkdir -p /supervise/rc-httpd-tls
>/supervise/rc-httpd-tls/run
chmod 775 /supervise/rc-httpd-tls/run
ed /supervise/rc-httpd-tls/run
i
#!/bin/sh
exec /usr/local/plan9/bin/listen1 tcp!domain.com!443 \
	/usr/local/bin/setuidgid _rc-httpd \
	/home/user/www/werc/bin/contrib/tcp443
.
w
q

We'll hold off on enabling the service until rc-httpd and werc are configured.

Create a log file

This can go wherever you like (or you can omit logging entirely), but for the sake of this example:

>/var/log/rc-httpd
chgrp _rc-httpd /var/log/rc-httpd
chmod g+w /var/log/rc-httpd

Edit the tcp80 script

The tcp80 script that ships with werc lists a default path to rc-httpd that probably doesn't exist on your system. Change your copy of tcp80 to point to the correct location:

ed /home/user/www/werc/bin/contrib/tcp80

ucspi-tools

The ucspi-tools tlss(1) program can be used to handle TLS for incoming TCP connections. After the TLS connection is established, tlss will spawn rc-httpd.

pkg_add ucspi-tools
openssl genrsa -out /etc/ssl/rc-httpd.server.key 2048
openssl req -new -key /etc/ssl/rc-httpd.server.key \
	-out /etc/ssl/rc-httpd.server.csr
openssl x509 -sha256 -req -days 365 \
             -in /etc/ssl/rc-httpd.server.csr \
             -signkey /etc/ssl/rc-httpd.server.key \
             -out /etc/ssl/rc-httpd.server.crt
chown root:_rc-httpd /etc/ssl/rc-httpd.server.csr /etc/ssl/rc-httpd.server.key
chmod 640 /etc/ssl/rc-httpd.server.csr /etc/ssl/rc-httpd.server.key

Create the tcp443 script

The tcp443 script is a counterpart to tcp80 that handles incoming TLS connections:

>/home/user/www/werc/bin/contrib/tcp443
chmod 775 /home/user/www/werc/bin/contrib/tcp443
ed /home/user/www/werc/bin/contrib/tcp443
i
#!/bin/rc
exec tlss \
	-c /etc/ssl/rc-httpd.server.crt \
	-k /etc/ssl/rc-httpd.server.key \
	/home/user/www/werc/bin/contrib/rc-httpd/rc-httpd \
	>>[2]/var/log/rc-httpd
.
w
q

Optional: Edit select-handler

The rc-httpd script needs to know what do with incoming requests. The default configuration hands any incoming requests to werc, which looks in werc/sites/$SERVER_NAME for a corresponding directory. The default configuration is sufficient for our example setup, but if a more granular approach is desired it may be customized thusly:

ed /home/user/www/werc/bin/contrib/rc-httpd/select-handler

Several examples of different select-handler configurations are documented in the 9front source: /rc/bin/rc-httpd/select-handler

A simple werc site

mkdir /home/user/www/werc/sites/domain.com
echo hello world >/home/user/www/werc/sites/domain.com/index.md

For more information about customizing werc see the werc website.

Enable rc-httpd

Finally, turn on the service:

ln -s /supervise/rc-httpd /service
ln -s /supervise/rc-httpd-tls /service

Make use of the usual daemontools features to examine service state, etc.