Blog based on Tornado, MongoDB, and Motor. To be used with MarsEdit.
Python CSS HTML JavaScript Shell
Fetching latest commit…
Cannot retrieve the latest commit at this time.


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