Skip to content

Serve a simple blog with an org-mode file and a little bit of templating.

Notifications You must be signed in to change notification settings


Folders and files

Last commit message
Last commit date

Latest commit



64 Commits

Repository files navigation


I use orgblog on my blog at but I’m sure you’ll come up with a nicer template than mine.


orgblog is available in PyPi, so installation is a simple pip install orgblog.

To get started, do a orgblog --install-default-conf --install-default-templates --install-test-file. This will populate ~/.orgblog.json, ~/.orgblog/collections/, and ~/.orgblog/templates/ so you can get up and running. Then just run the orgblog command to start the server on localhost.

~ $ orgblog 
* Running on (Press CTRL+C to quit)

You’ll probably want to configure things a little first, and more than likely customize your template some too.

What Is This?

There’s no shortage of advice online about how to set up a simple (or not-so-simple) blog using org-mode in Emacs. Most of this advice assumes a lot of things that aren’t true about me:

  • I am not that comfortable with writing/editing large globs of mostly impenetrable elisp source.
  • I don’t want a static site generator, since that adds a build step, and I’d rather be able to just make my edits and go (note that, despite this, orgblog does now support static site generation)
  • I don’t want to deal with the really-quite-confusing and dense HTML that org-mode’s default exporter comes coughs up.
  • I don’t want to export from org-mode to some other intermediate format (like Jekyll) on my way from org-mode to serveable HTML.

In short, my ideal solution didn’t exist, so I made it.


Your “blog” can have more than one collection. If you are creating a real blog, you will probably want to call this collection “posts”. Each collection is a single org-mode formatted file. The top-level headings in this file are assumed to be items in this collection.


orgblog looks for a site-wide configuration file in /etc/orgblog.json first. If there’s none there, it will check ~/.orgblog.json next. Finally it will use some default internal values. These are the configuration settings currently supported:


Default: What IP address the server listen on for web requests.


Default: 5000 What port the server will listen on for web requests.


Default: ~/.orgblog/static/ This is a directory where you can put additional static assets like images, javascript, or CSS files that your site needs. They will be served under /static/.


Default: ~/.orgblog/collections/ This is the full path to the directory containing org files which represent collections.


Default: ~/.orgblog/templates/ This is the full path to the directory containting collection templates. Each collection shoud have its own subdirectory with an items.html, item.html, and tag.html. This is better explained in the later section on templates.


Default: ["DONE"] This configures what TODO statuses orgblog will consider “done”. By default, this is only those posts marked DONE, but the option is a list and can contain any number of values. Add the emptry string (=”“=) in order to show posts with no status at all.


Once you have your site configured, you can


Templating uses the pystache library, which gives a familiar mustache or “double-hug” syntax. Templates are kept in the configured template_directory (see the section on configuration).

Main Template

The root page of your site (the one at /) is built from a template called index.html in the templates directory. This template has access to all collections via its context. For example, if you have a and a file in your collections_directory, the index.html template will have access to two collections: posts and projects.

Collection Templates

In addition to the index.html template, each collection needs two template files, a <collection_name>/items.html file and a <collection_name>/item.html.

items.html is used to construct the “index” page for that collection. It has in its context a list called {{#items}}, which contains the context of the whole collection, allowing you to write out a list.

item.html , while the latter is used to construct the individual item pages. It has in its context only the information about a single item, available in the variable called {{item}}.

In the context of a blog, items.html would be used for the /posts url, while items.html would be used for a url like /posts/2018-06-01-its-my-birthday-again.

tag.html is used for constructing a page which will show items in a collection with a particular tag. In the blog use-case, this would be a page like /posts/tag/hotdogs containing a list of posts with the hotdog tag. The context it receives is similar to the one items.html receoves except the {{#items}} list only contains the appropriately-tagged items, and there is an additional string variable {{tag}}= to tell the template what tag the page is for.

Static Generation

As of version 0.7.5, orgblog supports a --static flag which will output a set of static HTML files to a directory named _site in your current working directory. Note that all files will be given a .html suffix. If you want to serve these via Apache, but want to retain “pretty” urls without the .html suffix, use a .htaccess file (or edit the VirtualHost configuration) like this:

RewriteEngine On
RewriteCond %{REQUEST_FILENAME} !-f
RewriteRule ^([^\.]+)$ $1.html [NC,L]


Serve a simple blog with an org-mode file and a little bit of templating.







No packages published