Blog based on Tornado, MongoDB, and Motor. To be used with MarsEdit.
Python CSS HTML JavaScript Shell
Latest commit 83d230e Mar 16, 2016 @ajdavis Merge pull request #41 from boylea/master
Fix stumbling points in setup


Blog platform based on Tornado, MongoDB, and Motor. To be used with MarsEdit.



  • Frontend: Motor-Blog runs in Tornado. It is very fast.

  • Editing: Motor-Blog has no admin panel, but supports MarsEdit.

  • Comments: Motor-Blog does not support comments natively, I recommend a third-party Javascript comments API like Disqus.

  • Customization: Appearance is completely customizable.


  • Install MongoDB and run it on the default port on the same machine as Motor-Blog

  • pip install -r requirements.txt

  • To migrate from a prior WordPress blog with you'll need Pandoc


Development Deployment

Start MongoDB

mkdir data
mongod --dbpath data --logpath data/mongod.log --fork --setParameter textSearchEnabled=true

Copy motor_blog.conf.example to motor_blog.conf, edit it as desired. Start the application:

python --debug --config=motor_blog.conf --ensure-indexes

Visit http://localhost:8888/blog

Production Deployment

I run Motor-Blog on with Nginx at the front and four processes. Those processes and MongoDB are managed by Supervisor. I've provided example config files in this repository in etc/. If you have an Nginx version with WebSocket support (1.3.13 or later) then draft posts will autoreload when you update them from MarsEdit.

Run python --ensure-indexes at once when first installing Motor-Blog on a production MongoDB server. (If you see an error when using the search box, "Can't canonicalize query: IndexNotFound text index required for $text query", it means you haven't done this step. In any case, running Motor-Blog without indexes built will risk performance problems.)

MarsEdit setup

In MarsEdit, do "File -> New Blog." Give it a name and the URL of your Motor-Blog's home page. MarsEdit auto-detects the rest. You'll need to enter the username and password you put in motor_blog.conf. In the "General" tab of your blog's settings, I suggest setting "Download the 1000 most recent posts on refresh," since Motor-Blog can handle it. Under "Editing," set Preview Text Filter to "Markdown", and Image Size "Defaults To Full Size".

When you're editing a post, do "View -> Excerpt" to edit the post's meta-description. This text appears in Google results as a snippet, or when sharing a link to the post on Facebook. Motor-Blog refuses the post if the meta-description field is over 155 characters. Do "View -> Slug Field" to set a custom slug as the final part of the post's URL. If you leave the slug empty, Motor-Blog slugifies the title.

Finally, you'll want to customize how MarsEdit inserts images. This customization serves two purposes: first, we'll remove the width and height from img tags so Motor-Blog's responsive layout can fit them to the visitor's screen. Second, we'll set images' title text is set to the same value as their alt-text, since browsers display image titles as tooltips. Open the MarsEdit Media Manager and select an image. In the Media Manager's lower-right corner is a "Style" chooser, with the option "Customize...":

Alt text

Choose this and create a new image style with "opening markup" like this:

    style="display:block; margin-left:auto; margin-right:auto;"
    title="#alttext#" />


Motor-Blog renders Markdown with Python-Markdown. Plain inline code is surrounded by single backticks (``). Code blocks can be fenced in a number of styles, such as GitHub's:

print "foo"

The list of languages is whatever Pygments supports. The following are of interest to Python coders like me: py, py3, pytb and py3tb for tracebacks, and pycon for console sessions.

Using a feature in the latest Python-Markdown, you can highlight specific lines in a code block:

```python hl_lines="2"
# Line 1.
# Line 2. This will have a yellow background


  • Set your theme directory in motor_blog.conf.
  • The theme directory should contain a templates subdir with the same set of filenames as the example theme. Tornado templates or Jade templates are both supported.
  • Follow the example theme for inspiration.
  • The setting() function is available to all templates, and gives access to values in motor_blog.conf.

A Tour of the Code

  • Web application server
  • motor_blog/: Package code
    • web/
      • RequestHandlers for the blog's website
      • admin-templates/: Templates for login/out and viewing drafts
    • theme/: Default theme for, overridable with your theme
    • api/: The XML-RPC API that MarsEdit uses
    • schema definitions
    • text/
      • convert from Markdown into HTML for display, including some custom syntax
      • convert from the WordPress's particular HTML to markdown, for
      • convert from HTML to truncated plain text for all-posts page
    • tools/:
      • Tool for migrating from my old Wordpress blog to Motor-Blog. I wrote this tool when Motor didn't support GridFS, so it puts all media from Wordpress into single documents in the "media" collection, which brings us to...
      • Tool to migrate media from a single document per image in the "media" collection to GridFS.
    • Cache results from MongoDB, invalidate when events are emitted
    • Index definitions for --ensure_indexes
    • Configuration parsing