Release notes

The publishing mechanism used to produce this website is a topic of little interest, nonetheless, I’d like to, if only to keep a note of the work done and changes made. But first some trivia.

By 2010, I was fed-up with a popular open source web publishing software I’d been using since 2004. Its code base was changing so rapidly that I could not keep up. To quote Tom Preston-Werner, Blogging Like a Hacker (2008):

I already knew a lot about what I didn’t want. I was tired of complicated blogging engines like WordPress and Mephisto. I wanted to write great posts, not style a zillion template pages, moderate comments all day long, and constantly lag behind the latest software release.

On Sunday, October 19th, I sat down in my San Francisco apartment with a glass of apple cider and a clear mind. After a period of reflection, I had an idea. While I’m not specifically trained as an author of prose, I am trained as an author of code. What would happen if I approached blogging from a software development perspective? What would that look like?

By 2011, fatigued by bloat and potential vulnerabilities of open source web publishing software stack, Tom’s post caught-on. It helped people realise that writing one was not some dark art that needed an army of engineers and volunteers for it to be useful, thus renewing interest in the development and use of fit-for-purpose static site generators. One could also get rid of all the complexities of running and managing database instances, and keep them from corrupting over time, be it from upgrades or from encoding.

These trends helped re-assess my needs too. For instance, questioning the need to use traditional web service hosts, or the need for pre-requisites like LAMP stack to be able to host simple websites. Having such software in the cloud and shared across users amplified attack vectors for the hapless publishers. And for what really? For the comfort of publishing on the road by accessing an archaic login system without multi-factor authentication? It’s ridiculous in hindsight of course, but there was a time many of us thought that there really was no alternative.

In 2012, after years of grappling with software bloat, security gaffes, and latency of various web publishing services, I decided to take control of my publishing set-up. My objectives in maintaining control over publishing work-flow were:

After some searching and evaluating, I found Chisel — a simple python script to turn notes, written in markdown, into html pages, and auto-arrange them in a neatly linked structure. It employed Jinja, a minimal, performant template engine; git for tracking changes in both notes and code; and GitHub for hosting. I subsequently added a few features to Chisel I wanted for myself.

Both the model and the controller are local processes, having decided long ago that I would run nothing in the cloud. Only the view produced (from a combination of model and controller processes) is pushed to the host via git. (This eliminates the need for a feature-rich web server on the host, and is therefore ideal for hosting a locally generated static site.) Today I am able to say that after nine years of sustained use of this above set-up, it remains very usable. The code base has remained the same, with lines of code never exceeding more than a few overall, and it is as readable today as I had first found it. The only noteworthy maintenance I undertook was in 2019-20, when concerned by the need to phase out python2 code, I sat down to re-factor Chisel to run on python3. I did so without discernible change in code.

This is a set of release notes, covering features or updates, from that exercise done a year ago, and split into MVC design pattern.

Controller

Model

View

Building JSON feed (2025)

JSON is an open standard file format, which has been in existence since the early 2000s. Created by Douglas Crockford, it has a simple, dictionary-like structure, e.g.,

{
    "key" : "value",
}

In 2017, two entrepreneurs developed a JSON feed spec., leveraging the simplicity of JSON format. The spec is a lightweight alternative to XML-heavy formats (like RSS or Atom), and despite its recency, it enjoys mainstream support across feed reader apps.

The first I wrote a template to produce JSON feed for this web site was in 2020. Over the next few years, I dismantled the Atom feed, leaving only JSON feed as the channel to alert the subscriber of a new note, whenever I produced one.

While the spec allows html content, using content_text I think is more appropriate for a notification system. This is aside from being simpler and readable, and so that is what I use. Jinja, the templating engine I use, has some nice filters (viz., tojson, truncate, and striptags), making it easy to produce a JSON feed.

The template to produce a valid JSON feed for Chisel is as follows.

{% from 'sitesettings.j2' import site_title, site_author, site_url, site_desc -%}
{
  "version" : "https://jsonfeed.org/version/1.1",
  "user_comment" : "This feed lets you know when a new note is published. Copy the following URL -- {{ site_url }}/feed.json -- and add it to your feed reader.",
  "title" : "{{ site_author }}",
  "home_page_url" : "{{ site_url }}",
  "feed_url" : "{{ site_url }}/feed.json",
  "description" : "{{ site_desc | title }}",
  "authors" : [
    {
      "name" : "{{ site_author }}",
      "url" : "{{ site_url }}"
    }
  ],
  "icon" : "{{ site_url }}/inc/apple-touch-icon.png",
  "favicon" : "{{ site_url }}/inc/apple-touch-icon.png",
  "items": [
  {%- for entry in entries %}
    {
      "id" : "{{ site_url }}/{{ entry.url }}",
      "title" : "{{ entry.title }}",
      "url" : "{{ site_url }}/{{ entry.url }}",
      "content_text" : {{ entry.content|truncate|striptags|tojson }},
      "date_published" : "{{ entry.feed_date }}"
    }{%- if not loop.last %},{%- endif %}
  {%- endfor %}    
  ]
}

nginx (2025)

The 2025 version of setting up on a home network to serve a static local website is as follows. (Note: the file /etc/nginx/nginx.conf does not need editing at all, since it loads *.conf files under the conf.d folder.)

  1. Install nginx

    sudo apt update
    sudo apt install nginx-light
    
  2. Upload a folder to be served, e.g., ck.lo in the example above to be under /var/www/.

  3. Create a file named virtual.conf under /etc/nginx/conf.d, and populate it with the following:

    server {
        listen 80;
        server_name ck.lo;
        location / {
            root /var/www/ck.lo;
            index index.html;
            try_files $uri $uri/ $uri.html =404;
        }
        error_page 404 /404.html;
    }
    

    Add more server blocks to the file, if there is a need to serve more than one local website. Test it with sudo nginx -t to ensure there are no errors.

  4. Set permissions for the server folder /var/www

    sudo adduser $USER www-data
    sudo chown -R www-data:www-data /var/www
    sudo find /var/www -type d -exec chmod 755 {} \;
    sudo find /var/www -type f -exec chmod 644 {} \;
    
  5. Reload nginx

    sudo systemctl reload nginx
    
  6. Optional: In /etc/pihole/custom.list, set local DNS like so. The local IP address in the following is but an example.

    10.0.1.100 ck.lo
    

With this, the local website should be accessible at http://ck.lo