NAWP (NAWP Ain't WordPress) -- Minimal Blogging Engine in Chicken Scheme

This is very much a work in progress, and not everything is guaranteed to work just now.

NAWP stores content in an sqlite database. It is dynamic, not a static site generator. It is supposed to run as a CGI script.

Why Would Anyone Actually Want to Use it?

Here's a short list of reasons.

  • Minimum dependencies. No PHP, no external RDBMS. Just the binary and a CGI-capable web server. If you pass -static -L -static on the csc command line when building it, you can even have a fully-static binary with no external dependencies at all.
  • Because you don't need the features of a more capable platform; you just want a publishing tool with as little friction as possible.
  • Because you know and love Scheme. You can reason about it and fix it when it breaks. Rest assured, it will break.


Here is a list of the external Scheme libraries ("eggs" in Chicken Scheme parlance) that NAWP needs:

  • anaphora
  • atom
  • crypt
  • lowdown
  • matchable
  • rfc3339
  • sql-de-lite
  • srfi-1
  • srfi-13
  • sxml-transforms
  • uri-common

You'll also need a CGI-capable web server. I use lighttpd with mod_cgi enabled.

Copy nawp-site.scm to /etc/nawp-site.scm. Edit /etc/nawp-site.scm in your text editor of choice, customizing the variables blog-base-uri, blog-title, and blog-description to taste.

Once the dependencies are installed, run: csc nawp.scm

Copy the resulting binary to your cgi-bin directory.

Next, make the database: sqlite3 /var/lib/nawp/blog.db < schema.sql

Make it readable and writable by the user the CGI script will run as.

Add a new user. Run the script as the owner of the DB, with the adduser argument. For instance, to add a user named chris:

doas -u dbowner /path/to/nawp adduser chris 'Chris Brannon'

You'll be prompted for the password. Unfortunately it'll echo to stdout for now. Fixing that is going to require a little yak-shaving. Finally, you'll want to do some web server configuration. Here's a sample configuration snippet for lighttpd:

server.modules += ("mod_cgi", "mod_redirect", "mod_rewrite")

# Redirect ^/blog$ to /blog/, so that relative links resolve properly:
url.redirect = ("^/blog$" => "/blog/")

url.rewrite-once = (
  "^/blog/$" => "/cgi-bin/blog",
    "^/blog/(.+)$" => "/cgi-bin/nawp/$1"

# Assuming you want the old-school Apache-style /cgi-bin directory like I do:
$HTTP["url"] =~ "^/cgi-bin" {
   cgi.assign = ( "" => "" )


To make a post, visit https://yourdomain/blog/post-form and fill in the fields.

Just visiting https://yourdomain/blog will show the most recent posts. There is an atom feed at https://yourdomain/blog/feed.atom


To contribute, you can push to branches in this repository that have names starting with patch_. I borrowed this idea from Tim Vaughan, author of elpher et al. The difference is that Tim Vaughan uses the git:// protocol, where I use https://.

Note that you need to be using the canonical clone URL to push: https://the-brannons.com/git/nawp

I forgot to disable cgit's "dumb HTTP clone endpoint" feature, so if you cloned with a /cgit URL and want to contribute, you should do

git remote set-url origin 'https://the-brannons.com/git/nawp'

Roadmap / TODOs

I plan on adding an API. It will probably be the metaweblog XML-RPC API used by WordPress, or a slimmed-down version thereof. There are command-line tools for blogging with WordPress, and it would be nice to be able to use those with NAWP.

I may add Gemini support. I haven't quite decided how I feel about Gemini. At first blush, it seems quite compelling and worth the effort.

I may add support for alternative input formats like asciidoc. More likely, I'd consider replacing markdown with asciidoc and sticking to one single input format. Markdown is useful, but it is also poorly specified -- excepting CommonMark -- and underpowered.

Idle speculation: I wonder how hard it would be to add SXML as an output format to pandoc...

A comment system would be nice.