Org-Mode Publishing Static Site Generation

Table of Contents

Previously, I discussed changing the generation of this site. Specifically, using Org-Mode files with Pandoc and some Bash scripts to generate the site. However, today, I have changed the site again. Now, the site is generated entirely using Org-Mode.

The Intertubes overflow with previous posts about static site generation or blogging with only Org Mode. I focus mainly on a few details to make things work here. But first, motivation. Why change.


I wanted to transition the blog into a more general purpose site and I felt my hand-rolled generation would not be adequate. I did not want to go back to bigger tools like Hugo and friends. While these would certainly be capable, remaining in Org and Emacs seemed like the "winning" move.

I also switched from using my own Solarized CSS, to Simple CSS.

A nice benefit of this change is automatic table of contents generated for each post and easily disabled for pages where table of contents do not make sense. Another benefit was learning that many of the links in the previous posts were broken. Publishing does not generate sites with broken links.

Some Emacs Lisp

Defining an Org project is fairly straightforward, but some parameters to the publishing projects depend on the circumstance.

Preamble and Postamble

To handle the headers and footers of the site, I defined the following function to read in, now modified versions of, the previous header and footer HTML content.

(defun read-template (filename)
  "Read template contents from FILENAME."
    (insert-file-contents filename)

Then, this function can be used to load in the content of the template files:

(setq head-extra-template (read-template "templates/html_header.html"))
(setq header-template (read-template "templates/html_sub_header.html"))
(setq header-nav (read-template "templates/nav.html"))
(setq footer-template (read-template "templates/html_footer.html"))

Then for each project, the following keys are set:

:html-head-extra head-extra-template
:html-preamble header-nav
:html-postamble footer-template

Simple CSS Preamble + Postamble

To get the preamble and postamble to be styled right by SimpleCSS, the following keys were necessary:

:html-divs '((preamble "header" "")
             (content "div" "main")
             (postamble "footer" ""))


To publish the RSS feed, I needed to copy the ox-rss.el file wholesale so that it was accessible during the automated publishing.

Building and Publishing


With the build-site.el file defined, the Make target is quite simple.

.PHONY: org-publish
	emacs -Q --script ./build-site.el

GitHub Actions

In an earlier post, I described using AWS CodeBuild to automatically build site content and copy the files to S3. However, after one timed-out build attempted to put 15 GB of useless files into my S3 bucket and caused over 400,000 requests against the bucket, it was time to try something new.

While hosting with S3 and CloudFront is cheap, hosting with GitHub Pages is free. More than that, if I ever write something people are interested in, I do not need to worry about my CloudFront costs ballooning out of control.

Of course, this is not a real worry. CloudFront has only cost about $0.01 for a while, sometimes less.

The process of setting this up is straightforward and more up-to-date documentation is available from GitHub.

Parting Thoughts

Nothing is perfect, but overall, I am pleased with the result of switching to using Org Mode for publishing. There exists a learning curve– as with all things– however, not needing to develop and maintain the publishing scripts to the degree the custom rolled solution required is a relief. It may require some code to develop a new section or something else. But not nearly to the degree the old method required.

Certainly, changing the hosting was not intended. I started the publishing change with the intent that it would still be hosted with AWS CloudFront and AWS S3. Unfortunately, the build issues described above and my own second guessing the rationale for hosting with AWS persuaded me to switch.