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:
- To write and present code, math, and prose effortlessly
- Enable login-less cryptographically-secure publishing
- Ensure portability of notes together with track changes
- Maintain bare bones, readable, safe, and low-dependency code base
- Use a decent template engine to be able to do more with less code
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
- Date is ISO 8601 compliant (new)
- Fenced code markdown extension enabled (new)
- Generator specific config file (new)
- Re-factored to python 3 (new)
- Select contributions sent upstream via pull requests (update)
- Taxonomy (tag) feature added (new, Nov 2023)
Model
- Feed templates now in JSON (new)
- Keyboard-only navigation Alt + ( / , j , k ) with circular return (update)
- Homepage is now also the archive page (update)
- Template parameters: single config file, selective imports (new)
- Templates modularised with child templates (new)
- Home template updated to support tags (new, Nov 2023)
View
- Custom font calls eliminated (update)
- Dark mode honouring OS-set appearance (update)
- Numerous template snippets re-factored to be modular (update)
- Re-design, html5 and css3 compliant (new)
- Render math with KaTeX engine (new)
- Snippets re-formatted using black for improved readability (new)
- Highlight.js and KaTeX combined to only load on demand
- A clutter-free access to text-only web browsers like lynx, links
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.)
-
Install nginx
sudo apt update sudo apt install nginx-light
-
Upload a folder to be served, e.g.,
ck.lo
in the example above to be under/var/www/
. -
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. -
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 {} \;
-
Reload nginx
sudo systemctl reload nginx
-
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