Bill Agee's blog

🤔 Reflections on test infrastructure, with a twist of user empathy.

Switching from Octopress to Pelican

Or: What we blog about when we blog about blogs

🐙 ➡️ 🐍

This post is the story of how I switched the underlying framework for this blog from Octopress to Pelican.

And I added a side quest: Like many Octopress users, I grew fond of the default Octopress theme, and wanted to keep it after moving to Pelican.

Keeping the Octopress theme turned out to be easy; the pelican-octopress-theme github repo was what I needed:

And for other tips, Google revealed blog posts from other folks who made the Octopress-to-Pelican switch over the years. Trip reports I referred to were:

The plan

First off, after reading the docs, I wrote down the steps I assumed would be involved with the move; here they are:

  1. Create and activate a virtualenv, then use pip to install pelican
  2. Use the pelican-quickstart util to set up a barebones Pelican blog, as a starting point for the move
  3. Get used to launching a dev server to preview changes
  4. Apply the pelican-octopress-theme to the barebones blog
  5. Bring my old blog's CSS and sidebar customizations into pelican-octopress-theme
  6. Create a public github repo containing the work so far
  7. Copy the old Markdown post files and images from my Octopress dir to my pelican repo
  8. Edit posts as needed to get them to display properly
  9. Back up the contents of my existing blog's s3 bucket (for easy rollback if the first deploy doesn't go smoothly)
  10. Publish the new files to s3!

The reality

Based on the outline above, here's what actually happened when I started carrying out the plan:

  1. Installing pelican

    For this step I set up a new virtualenv and installed the pelican and markdown packages:

    virtualenv env
    . env/bin/activate
    pip install pelican markdown

    For the record, I was using OS X, Python 2.7.12 from Macports, and Pelican 3.6.3.

  2. Running pelican-quickstart

    This part of the process went smoothly. The quickstart util didn't bring up any surprises, and produced the files that became the blog you're reading now.

    Here's a log of the input I gave pelican-quickstart to bring up a site with a dev server script, Makefile, and s3 publishing support:

    > Where do you want to create your new web site? [.]
    > What will be the title of this web site? Bill Agee's blog
    > Who will be the author of this web site? Bill Agee
    > What will be the default language of this web site? [en]
    > Do you want to specify a URL prefix? e.g.,   (Y/n) n
    > Do you want to enable article pagination? (Y/n) n
    > What is your time zone? [Europe/Paris] America/Los_Angeles
    > Do you want to generate a Fabfile/Makefile to automate generation and publishing? (Y/n) Y
    > Do you want an auto-reload & simpleHTTP script to assist with theme and site development? (Y/n)
    > Do you want to upload your website using FTP? (y/N)
    > Do you want to upload your website using SSH? (y/N)
    > Do you want to upload your website using Dropbox? (y/N)
    > Do you want to upload your website using S3? (y/N) y
    > What is the name of your S3 bucket? [my_s3_bucket]
    > Do you want to upload your website using Rackspace Cloud Files? (y/N)
    > Do you want to upload your website using GitHub Pages? (y/N)
    Done. Your new project is available at /Users/bill/github/billagee/
  3. Bringing up a dev server to preview changes

    This was super easy. Assuming you answered yes to the auto-reload & simpleHTTP question in pelican-quickstart, just run make devserver.

    Then point your web browser at localhost:8000 to browse your site.

    To stop your dev server, run make stopserver.

  4. Apply pelican-octopress-theme to the demo blog

    At this point I paused to see what the docs had to say about how to use themes in Pelican.

    To try out the stock pelican-octopress-theme, first clone its repo:

    git clone \

    Then install it in your site with the pelican-themes util:

    pelican-themes --install ~/github/duilio/pelican-octopress-theme

    There's one more step - to make sure the dev server can find the theme, edit the file in your pelican dir, and place the --theme-path option and value in the PELICANOPTS variable:

    # In - replace the empty PELICANOPTS= var if it's present:
    PELICANOPTS="--theme-path ~/github/duilio/pelican-octopress-theme"

    This is a good time to make the same change in the Makefile in the root of your site, since you'll be needing it there too (note that the double quotes around the value are left out):

    PELICANOPTS=--theme-path ~/github/billagee/pelican-octopress-theme

    Restart your dev server after making those changes, and reload the site in your browser - you should then see the Octopress theme in place:

    make stopserver && make devserver
  5. Making a test post

    At this point I added a new step to the original plan: Learning how to create a post.

    To do that using Markdown (adapted from the content docs), you can cat out a post file to disk like so, if you're in your site's root dir:

    # Again, this assumes your current working dir is your blog's root dir:
    cat > content/ << EOL
    Title: My title
    Date: 2016-08-20 12:30
    Category: Python
    Tags: pelican, publishing
    Slug: my-test-post
    Authors: Your Name Here
    Summary: Short version for index and feeds
    This is the content of my test post.
  6. Bring my old blog's color and sidebar customizations into pelican-octopress-theme

    This is, of course, an optional step, but I wanted to change the header background color of the Octopress theme, and rearrange the sidebar.

    This required a bit of tinkering, but it wasn't too bad.

    To change the header background color in pelican-octopress-theme, I first made my own fork of the original repo.

    Then, I cloned my fork, and changed the $header-bg value in the SASS file where it lives: sass/base/_theme.scss

    //$header-bg: #333 !default; // default octopress gray
    $header-bg: #35206f !default; // likewise purple

    There's one more step required - recompiling the theme's SASS files using the compass util. To install sass and compass and update the theme with your changes, cd to the root of your pelican-octopress-theme fork, and:

    # Run this in your pelican-octopress-theme root dir
    gem install sass compass
    compass compile
  7. Create a public github repo containing the work so far

    Not much to say here, except that you might be interested in the .gitignore file I created before pushing my repo:


    Omit the output dir from your .gitignore if you want to keep your generated site files under version control.

  8. Copy the old Markdown post files from my Octopress dir to my pelican repo

    This is where things began to get real. I started by coping the post files from my sources/_posts Octopress dir to content/. I then committed everything as-is before making edits.

    The first step was to convert the old Octopress post metadata, for example:

    layout: post
    title: "Dockerized Ghostdriver Selenium Tests"
    date: 2016-02-14 00:23
    comments: true
    categories: Docker Linux Selenium WebDriver Automation PhantomJS Python Testing
 the corresponding Pelican Markdown:

    Title: Dockerized Ghostdriver Selenium Tests
    Date: 2016-02-14 00:23
    Tags: Docker, Linux, Selenium, WebDriver, Automation, PhantomJS, Python
    Slug: dockerized-ghostdriver-selenium-tests

    Note the addition of the Slug field, and replacing categories: with Tags, since Pelican offers both categories AND tags. And Pelican tags seem akin to Octopress categories.

  9. Edit posts as needed to get them to display properly

    I noticed a few indentation changes to existing code blocks in my posts were required to get them to display properly.

    In the end, I switched over to using code blocks prefixed with :::, for syntax highlighting with CodeHilite. Here's an example:

  10. Converting Octopress image tags

    There was another extra step required to get images in old posts to display - moving Octopress Markdown posts to Pelican means embedded images that use the Octopress {% img %} tag won't carry over directly without edits (or the liquid_tags Pelican plugin).

    I didn't have too many images in my old posts, so I just replaced my old Octopress image tags, such as:

    {% img /images/fancybox.png 'fancybox screenshot' %}

    ...with the Pelican attach syntax:

    ![Fancybox Screenshot]({attach}images/fancybox.png)

    This was also the point when I finished copying all the image files from my old Octopress dir (source/images/) into my Pelican blog's content/images/ dir.

  11. Back up the contents of my existing s3 bucket before copying any new files to the bucket

    Not much to say here. s3cmd sync was my means of doing this.

  12. Publish the new files to s3!

    With your AWS credentials in ~/.s3cfg, just set your s3 bucket's name in your Pelican dir's Makefile, in the S3_BUCKET variable.

    Then, to publish your changes to your s3 bucket:

    make clean
    make s3_upload
  13. Manually fixing the Content-Type value for main.css

    I ran into a hiccup here - after publishing my files to s3, the MIME type guessing done during the upload apparently didn't work, so my main.css file was served by s3 as text/plain.

    This resulted in the published copy of the blog in s3 displaying without CSS being applied; so, the appearance of the blog was totally broken in all browsers I tried. Oops.

    Presumably this will only affect you if you're publishing to s3 like me; I didn't try deploying with Dropbox or the other options.

    I worked around the problem by using the AWS console to manually change the Content-Type header value S3 serves up for my main.css file. (I still need to find a real fix for this, or at least a way of doing it with s3cmd.)

    Steps for the fix were:

    • After make s3_upload completes, log in to the AWS s3 console.

    • In the UI, navigate to: All Buckets > /YOUR_BUCKET/theme/css

    • Right-click main.css, and view its properties

    • Under "Metadata", set the Content-Type key to text/css and save.

  14. Using the pelican-alias plugin to create .html aliases to posts

    I'd forgotten that my very oldest Octopress posts were actually raw HTML migrated from Blogger years ago - long ago I jammed that content into Markdown files, and each Markdown file contained one massive, single-line <div> exported from Blogger.

    Ugh! I couldn't let that stand, so I took the time to convert those old HTML posts to proper Markdown.

    I then realized a few of those old Blogger-era HTML posts were still showing up in Google results, with their original .html extensions (which Pelican and Octopress don't create).

    In the Octopress blog I'd resorted to creating s3 aliases for those old posts at publish time, in the bash script I used to upload everything with s3cmd.

    That resulted in posts whose URLs ended in 2012-08-foo/ getting matching 2012-08-foo.html siblings, in case someone visited the old Blogger URL.

    In Pelican, you can use the pelican-alias plugin to create .html aliases for posts, which worked fine for me. See that plugin's docs for more info.

    For more it boiled down to installing and activating the plugin, then adding an extra bit of metadata to the ancient posts that needed an .html alias:

    Alias: /2011/07/selenium-2-net-test-drive.html
  15. Google Analytics

    To set up Google Analytics, I put my GA ID in the file in the site's root dir, in the GOOGLE_ANALYTICS var.

  16. Modifying the order of items in the Octopress theme sidebar

    My old blog had some custom tweaks to the sidebar; preserving those (and adding some new ones) was mainly a matter of editing this file in my pelican-octopress-theme fork:


    The commit history for my pelican-octopress-theme fork tells the full story of the sidebar.

  17. Github sidebar fix

    Either due to a bug in the theme, or as a result of my sidebar tweaks, the Github chunk of the sidebar was refusing to fetch the list of my github repos.

    To get that working, I made this JS tweak in my fork's copy of pelican-octopress-theme/templates/_includes/github.html - namely pulling in jQuery.

    This seems rather...not great, but it works for now:

         {% if GITHUB_SHOW_USER_LINK is defined %}
           <a href="{{ GITHUB_USER }}">@{{ GITHUB_USER }}</a> on GitHub
         {% endif %}
    +    <script src="" integrity="sha256-cCueBR6CsyA4/9szpPfrX3s49M9vUU5BgtiJj06wt/s=" crossorigin="anonymous"></script>
         <script type="text/javascript">
    -      $.domReady(function(){
    +      $(document).ready(function(){
               if (!window.jXHR){
                   var jxhr = document.createElement('script');
                   jxhr.type = 'text/javascript';


That's all for now, I suppose! This concludes my first Pelican post.