Blogging with org-page

By Calum MacRae

January 18, 2015

I moved my blogging framework from Jekyll over to org-page yesterday, so I figured I'd write about it!

Why I moved

Before I moved to org-page yesterday, I'd been blogging with Jekyll for a while. Granted, I don't write often (something which is going to change).

I like Jekyll - it's simple. There's not really any messing around. You just write your posts in markdown, then use git and post-commit hooks to generate/publish the site on your remote system. Not to mention, you can also use jekyll serve to serve up your site locally, so you can see how your changes appear, prior to committing.

As I'm writing, I really do find myself wondering if I had a good reason to move to org-page. If simply wanting to blog using Emacs and org-mode is a good reason, well, there you have it.

I spend all day in Emacs, both at home and at work, a lot of which I'm sat in org-mode. I'm still fairly new to Emacs, I haven't even been using it a year. But I find myself in the position many do: I just want to do everything from Emacs. It really is an operating system of its own. So, I suppose, quite naturally I wanted to move my writing to an Emacs based framework.

Writing markdown in Emacs, then using magit to commit and push my changes was just fine. But I really do love org-mode, as everyone should! So, the prospect of writing in org-mode captivated me.

That's quite enough meaningless rambling, trying to justify why I switched from a perfectly good framework to another perfectly good framework…

The stack (wow, so DevOps)

So, org-page takes org-mode syntax, then spits out HTML, just like most static site generators take a more simplistic markup language and churn out HTML. What's nice about org-page is that you have a source branch, where all your .org files sit, then, upon invoking M-x op/do-publication, you have the option to send the generated HTML to either a directory, or, dump them into the master branch. When you opt to send your HTML to the master branch, you also have the option to auto-commit & auto-push (if you have a remote repo set-up). I think this is really nice, and ties in really well with how I opted to handle the deployment of my site.

Although I'm a puppeteer by day, at work, my infrastructure at home is not nearly as diverse and sophisticated. So I opted to use Ansible. That's not to say Ansible can't handle diverse/sophisticated infrastructures, it certainly can - I have my reasons (I'll write about my experiences with Ansible in a future post, for now, let's focus on this "stack" ;)). Whilst using Ansible at home for managing my little environment, I quite often use it's git module. It's really handy for ensuring the latest code is deployed to systems. I figured this went hand in hand with exactly what I was looking to do: publish my post from org-page, auto-commit/push to the master branch hosted on my GitLab host, then Ansible comes along and deploys the latest publication to nginx on my blog host.

This was all really simple to get it up and running. Each of the services mentioned above I run in "smart zones" on the incredible SmartOS, all on a little HP Proliant Microserver (Gen 7).

The Git service used here really doesn't matter, nor does the webserver software. It could be a simple Git repo on the filesystem with no frontend, and any webserver could be used, like Apache or httpd.

Chuck it together in Ansible

The only part I suppose I really need to detail here is the Ansible code I threw together to do it. It's so simple, as most stuff is with Ansible, it only took me a few minutes!

Let's first take a look at a snippet from my inventory file:


Obviously, this is my collection of webservers. Simple enough. The host we're interested in is

Next up, here's the little playbook I threw together, along with it's defaults bellow:

# File: roles/webservers/tasks/main.yml
  - name: Ensure nginx is installed
    pkgin: name=nginx state=present

  - name: Ensure nginx is running & enabled
    service: name=nginx enabled=yes state=running

  - name: Ensure site content is up to date
    git: repo={{ site_repo }} dest={{ site_dest }} update=yes accept_hostkey=yes
    when: site_uses_git
# File: roles/webservers/defaults/main.yml
site_uses_git: False

As you can see, in the last "play" of the playbook 'Ensure site content is up to date', there's a conditional - denoted by when. This evaluates the variable site_uses_git for a boolean value. The code above it (simply ensuring some code is up to date) will only be run when site_uses_git evaluates to True. I've set the default value for this to be False in the roles/webservers/defaults/main.yml file, as right now my blog is the only host that I need this functionality for.

For the latest site data to be deployed to, the site_uses_git variable needs to be set to True, also the site_repo & site_dest variables need values. These are set within the host_vars/ directory, in a YAML file with the name of the FQDN of the system you want to inherit the contained code:

# File: host_vars/

site_uses_git: True
site_repo: ssh://
site_dest: /opt/local/etc/nginx/org_page
And there you have it! I have a playbook called site.yml which ensures common properties are as desired across particular nodes in my infrastructure. The webservers playbook is included in this run:

- name: Apply webserver configuration
  gather_facts: False
  hosts: webservers

    - webservers

so any time I do M-x op/do-publication and commit/push to the master branch of my repo, Ansible comes along and deploys the HTML to any time within 30 minutes. I could of course have this interval be more frequent, or manually run the playbook myself if I wanted the content to be updated sooner for any reason.

So, there you have it

Using Emacs, Git, and Ansible to deploy a static site. Quick to set up, and hassle free once it's all in place :)

Posted on:
January 18, 2015
5 minute read, 1019 words
emacs org-mode writing
See Also:
A Nix overlay for Emacs 27 with the 'emacs-mac' patches
Emacs: Making NeoTree work with Perspectives
E-mail in Emacs with mu4e on OS X