WLOG - notes something different


9front / plan9 provide plenty of tools for "web development" and hosting. But it is more of a "build your own solution" kind of affair.

On 9front a basic web server called rc-httpd is already included in the base installation.

The rest can/must be found through extra software or wild git repos.

rc-httpd (web server)

Setting up rc-httpd requires us to edit service file /bin/service/tcp80 (optionally /bin/service/tcp80.namespace) and rc-httpd config file /bin/rc-httpd/select-handler.

setting up service - unprivileged user (none)

Plan9 uses /bin/service/protocolPORT files to define a service running on that port, or more correctly, what to run when a request comes to that particular port. Directory /bin/service starts services with an unprivileged user "none". Additional /bin/service/protocolPORT.namespace files are used to set up the namespace (environment) for that service. If a name starts with !, that means the service is disabled.


Handle incoming request on port 80 (http) with the rc-httpd script and redirect output to a log file:

exec /rc/bin/rc-httpd/rc-httpd >>[2]/sys/log/www

setting up service - as specifiv user (web)

Same as for unpriviled user but files are in /bin/service.auth and are run as the system owner. There you can start it as the system owner or as another user.


auth/as web /rc/bin/rc-httpd/rc-httpd >>[2]/sys/log/www


Modifying the distributed example present in /bin/service, we bind a directory with writable permissions to anybody in to /tmp, since our website framework will require writable space for cache generation. In our case, a tmp folder withing a web user with "o+w" permission set.

mount -aC #s/boot /root $rootspec
# kernel devices
bind #c /dev
bind #d /fd
bind -c #e /env
bind #p /proc
#unknown#bind -a #l /net
bind -a #I /net
bind /root/$cputype/bin /bin
bind /root/rc /rc
bind -a /rc/bin /bin
chdev Mcde|pslI/
# grab just our webroot
#bind /root/usr/web /srv
# or bind in the actual root
bind -a /root /
# cutom: bind srv to access sensors
bind  #s /srv
# custom: bind writable dirs for cache and sensors
bind -c /usr/web/www/tmp /tmp
bind -c /usr/web/www/mnt /mnt
# have /usr/web/www/mnt/shmsensors folder already created
mount -a /srv/shmsensors /mnt/shmsensors
unmount /root
chdev -r Ms

/bin/service/tcp443 - untested

Currently, handling incoming request on port 443 (https) is done with nginx as a reverse proxy, redirecting traffic to port 80.

In theory, the same would be done here, handle authentication (certificates) and call rc-httpd on port 80.

exec tlssrv -c /sys/lib/tls/cert -l /sys/log/https /bin/service/tcp80 $*

Now, acquiring the certificates is another story. One could hack and get LetsEncrypt certificates somewhere else and transfer them to the system. Or, one could use auth/acmed, that ships with 9front, and get the LetsEncrypt certificates that way.

configuring the web server

Now that the request is accepted and transferred to rc-hhtpd, it needs to be set up how to handle it.


In our case, instead of using static-or-index handler to list or serve static pages, we use static-or-cgi handler to run werc framework and do page generation.

rfork n
switch($SERVER_NAME) {
case offbeatpursuit.com
#   FS_ROOT=/usr/web/www
#   exec static-or-index
    exec static-or-cgi /usr/web/www/werc/bin/werc.rc
case *
    error 503

werc (framework)

Werc - A sane web anti-framework developed and used by 9front comity.


Follow hte instructions in werc notes.

barf (werc plugin)

One of the external apps developed for werc.


Installed by cloning it with hg from https://code.9front.org/hg/barf in to werc/apps directory

configuration (blog - subdirectory example)

Create a directory for blog. Barf was not designed to work as in a subdirectory of the domain, but in the root. Some patching is required: diff. There might be more as time goes by. It might even be accepted into barf at some point.

Inside, create a UNDERSCOREwerc subdirectory. Inside UNDERSCOREwerc directory, create a config file and a barf subdirectory. Inside barf directory, create another config file.

|-- _werc
  |-- config
  |-- barf
    |-- config

The config file in UNDERSCOREwerc directory should a setting to enable barf, with other optional werc settings:

conf_hide_paths src

The config file in barf directory should contain barf settings:

barf_type=blog # blog, image, log, paste
require_login=0 # if not logged in, redirect to /login
allow_anon=0 # allow posts without logging in
show_disqus=0 # include disqus comments template # from _werc/barf/disqus

To generate a list list of tags (that can be later used for a clickable tag index), there is a script bundled in barf, that can be run from the blog directory:


This will generate a file called tags.

This file can be then used to create an html file with clickable links. A script is usefull for that.

For example, save it as halt (HEADER with ALL LINKED TAGS) in /PATHtoWERC/apps/barf/bin.

With this script, run from the blog directory, a header file will be generated in blog/UNDERSCOREwerc/barf subdirectory:


This can be then desplayed above the blog by enabling the header:



Let's make sure we don't run out of space with log files. Found on only9fans.


Installed by cloning it git/clone from git://shithub.us/garden/logrotate somewhere, then moving the logrotate script to $user/bin/rc.

The $user should be the system owner. If you don't know which user it is, it is probably glenda.

Also, make sure you have cron set up and running.


Edit the variables in the script itself to set log file location, which files, size and number of generations.

The logrotate script is run using cron. Check if /cron/$user/cron exists. If not, run auth/cron -c to create the appropriate directories and files.

Add the definition (time system command) to the cron file /cron/$user/cron. In our case, once per hour:

# logrotate
0 * * * * $sysname /usr/glenda/bin/rc/logrotate

Note: "$sysname" should be the actual system name of the computer or keyword local if run on the local computer.