The Nikola Handbook

Version: 5.2
Author: Roberto Alsina <ralsina@netmanagers.com.ar>

Contents

All You Need to Know

After you have Nikola installed:

Create a site:
nikola init mysite
Create a post:
nikola new_post
Edit the post:
The filename should be in the output of the previous command.
Build the site:
nikola build
Start the test server:
nikola serve
See the site:
http://127.0.0.1:8000

That should get you going. If you want to know more, this manual will always be here for you.

DON'T READ THIS MANUAL. IF YOU NEED TO READ IT I FAILED, JUST USE THE THING.

On the other hand, if anything about Nikola is not as obvious as it should be, by all means tell me about it :-)

What's Nikola and what can you do with it?

Nikola is a static website and blog generator. The very short explanation is that it takes some texts you wrote, and uses them to create a folder full of HTML files. If you upload that folder to a server, you will have a rather full-featured website, done with little effort.

It's original goal is to create blogs, but it supports most kind of sites, and can be used as a CMS, as long as what you present to the user is your own content instead of something the user generates.

Nikola can do:

Since Nikola-based sites don't run any code on the server, there is no way to process user input in forms.

Nikola can't do:

Keep in mind that "static" doesn't mean boring. You can have animations, slides or whatever fancy CSS/HTML5 thingie you like. It only means all that HTML is generated already before being uploaded. On the other hand, Nikola sites will tend to be content-heavy. What Nikola is good at is at putting what you write out there.

Getting Help

Why Static?

Most "modern" websites are dynamic in the sense that the contents of the site live in a database, and are converted into presentation-ready HTML only when a user wants to see the page. That's great. However, it presents some minor issues that static site generators try to solve.

In a static site, the whole site, every page, everything, is created before the first user even sees it and uploaded to the server as a simple folder full of HTML files (and images, CSS, etc).

So, let's see some reasons for using static sites:

Security

Dynamic sites are prone to experience security issues. The solution for that is constant vigilance, keeping the software behind the site updated, and plain old good luck. The stack of software used to provide a static site, like those Nikola generates, is much smaller (Just a webserver).

A smaller software stack implies less security risk.

Obsolescense

If you create a site using (for example) Wordpress, what happens when Wordpress releases a new version? You have to update your Wordpress. That is not optional, because of security and support issues. If I release a new version of Nikola, and you don't update, nothing happens. You can continue to use the version you have now forever, no problems.

Also, in the longer term, the very foundations of dynamic sites shift. Can you still deploy a blog software based on Django 0.96? What happens when your host stops supporting the php version you rely on? And so on.

You may say those are long term issues, or that they won't matter for years. Well, I believe things should work forever, or as close to it as we can make them. Nikola's static output and its input files will work as long as you can install a Python > 2.6 in a Linux, Windows, or Mac and can find a server that sends files over HTTP. That's probably 10 or 15 years at least.

Also, static sites are easily handled by the Internet Archive.

Cost and Performance

On dynamic sites, every time a reader wants a page, a whole lot of database queries are made. Then a whole pile of code chews that data, and HTML is produced, which is sent to the user. All that requires CPU and memory.

On a static site, the highly optimized HTTP server reads the file from disk (or, if it's a popular file, from disk cache), and sends it to the user. You could probably serve a bazillion (technical term) pageviews from a phone using static sites.

Lockin

On server-side blog platforms, sometimes you can't export your own data, or it's in strange formats you can't use in other services. I have switched blogging platforms from Advogato to PyCs to two homebrewed systems, to Nikola, and have never lost a file, a URL, or a comment. That's because I have always had my own data in a format of my choice.

With Nikola, you own your files, and you can do anything with them.

Features

Nikola has a very defined featureset: it has every feature I needed for my own sites. Hopefully, it will be enough for others, and anyway, I am open to suggestions.

If you want to create a blog or a site, Nikola provides:

Also:

Installing Nikola

This is currently lacking on detail. Considering the niche Nikola is aimed at, I suspect that's not a problem yet. So, when I say "get", the specific details of how to "get" something for your specific operating system are left to you.

The short version is: pip install https://github.com/ralsina/nikola/archive/master.zip

Longer version:

  1. Get Nikola
  2. Install dependencies. To do that, either:
    1. pip install -r requirements.txt or...
    2. Install your distribution's packages for all the things mentioned below, if they exist, or...
    3. Get all of these manually (but why?, use requirements.txt):
      1. Get python, if you don't have it.
      2. Get doit
      3. Get docutils
      4. Get Mako
      5. Get PIL (or Pillow)
      6. Get Pygments
      7. Get unidecode
      8. Get lxml
      9. Get yapsy
      10. Get configparser
  3. run python setup.py install

After that, run nikola init --demo sitename and that will create a folder called sitename containing a functional demo site.

Nikola is packaged for some Linux distributions, you may get that instead.

Getting Started

To create posts and pages in Nikola, you write them in one of the supported input formats. Those source files are later converted to HTML The recommended formats are restructured text and Markdown, but there is also support for textile and WikiCreole and even for just writing HTML.

First, let's see how you "build" your site. Nikola comes with a minimal site to get you started.

The tool used to do builds is called doit, and it rebuilds the files that are not up to date, so your site always reflects your latest content. To do our first build, just run "nikola build":

$ nikola build
Scanning posts  . . done!
.  render_posts:stories/manual.html
.  render_posts:posts/1.html
.  render_posts:stories/1.html
.  render_archive:output/2012/index.html
.  render_archive:output/archive.html
.  render_indexes:output/index.html
.  render_pages:output/posts/welcome-to-nikola.html
.  render_pages:output/stories/about-nikola.html
.  render_pages:output/stories/handbook.html
.  render_rss:output/rss.xml
.  render_sources:output/stories/about-nikola.txt
:
:
:

Nikola will print a line for every output file it generates. If we do it again, that will be much much shorter:

$ nikola build
Scanning posts  . . done!

That is because doit is smart enough not to generate all the pages again, unless you changed something that the page requires. So, if you change the text of a post, or its title, that post page, and all index pages where it is mentioned, will be recreated. If you change the post page template, then all the post pages will be rebuilt.

Nikola is mostly a series of doit tasks, and you can see them by doing nikola build list:

$ nikola build list
Scanning posts  . . done!
build_bundles
copy_assets
copy_files
deploy
redirect
render_archive
render_galleries
render_indexes
render_listings
render_pages
render_posts
render_rss
render_site
render_sources
render_tags
sitemap

You can make Nikola redo everything by calling nikola build forget, you can make it do just a specific part of the site using task names, for example nikola build render_pages, and even individual files like nikola build render_indexes:output/index.html

Nikola also has other commands besides build:

$ nikola help
Usage: nikola command [options]

Available commands:

nikola bootswatch_theme: Given a swatch name and a parent theme, creates a custom theme.
nikola build: Build the site.
nikola check: Check the generated site
nikola deploy: Deploy the site
nikola import_wordpress: Import a wordpress site from a XML dump (requires markdown).
nikola init: Create a new site.
nikola install_theme: Install a theme into the current site.
nikola new_post: Create a new post.
nikola serve: Start test server.

For detailed help for a command, use nikola command --help

The serve command starts a web server so you can see the site you are creating:

$ nikola serve
Serving HTTP on 127.0.0.1 port 8000 ...

After you do this, you can point your web browser to http://localhost:8000 and you should see the sample site. This is useful as a "preview" of your work.

By default, the serve command runs the web server on port 8000 on the IP address 127.0.0.1. You can pass in an IP address and port number explicity using -a IP_ADDRESS (short version of --address) or -p PORT_NUMBER (short version of --port) Example usage:

$ nikola serve --address 0.0.0.0 --port 8080
Serving HTTP on 0.0.0.0 port 8080 ...

Creating a Blog Post

A post consists of two files, a metadata file (post-title.meta) and a file containing the contents written in restructured text (post-title.txt), markdown or HTML. Which input type is used is guessed using the post_compilers option in conf.py but by default, the extensions supported are:

.txt .rst
Restructured Text
.md .markdown .mdown
Markdown
.htm .html
HTML

The default configuration expects them to be placed in posts but that can be changed (see below, the post_pages option)

You can just create them in posts or use a little helper task provided by Nikola:

$ nikola new_post
Creating New Post
-----------------

Enter title: How to make money
Your post's text is at:  posts/how-to-make-money.txt

The content of that file is as follows:

.. title: How to make money
.. slug: how-to-make-money
.. date: 2012/09/15 19:52:05
.. tags:
.. link:
.. description:
Write your post here.

The first line is the title. The second one is the pagename. Since often titles will have characters that look bad on URLs, it's generated as a "clean" version of the title. The third line is the post's date, and is set to "now".

You can add three more optional lines. A fourth line that is a list of tags separated with commas (spaces around the commas are ignored):

programming, python, fame, fortune

A fifth line that's a URL for an original source of the post, and a sixth line that's the page description.

Note

The Two-File Format

Nikola originally used a separate .meta file. That will still work! The format of the meta files is the same as shown above, but without the explanations:

How to make money
how-to-make-money
2012/09/15 19:52:05

If you are writing a multilingual site, you can also create a per-language post file (for example: how-to-make-money.txt.es). This one can have two lines of metadata:

  1. The translated title for the post or page
  2. A translated version of the pagename

You can edit these files with your favourite text editor, and once you are happy with the contents, generate the pages as explained in Getting Started

Currently supported languages are

If you wish to add support for more languages, check out the instructions at the theming guide.

The post page is generated using the post.tmpl template, which you can use to customize the output.

The place where the post will be placed by new_post is based on the post_pages configuration option:

# post_pages contains (wildcard, destination, template, use_in_feed) tuples.
#
# The wildcard is used to generate a list of reSt source files (whatever/thing.txt)
# That fragment must have an associated metadata file (whatever/thing.meta),
# and opcionally translated files (example for spanish, with code "es"):
#     whatever/thing.txt.es and whatever/thing.meta.es
#
# From those files, a set of HTML fragment files will be generated:
# cache/whatever/thing.html (and maybe cache/whatever/thing.html.es)
#
# These files are combinated with the template to produce rendered
# pages, which will be placed at
# output / TRANSLATIONS[lang] / destination / pagename.html
#
# where "pagename" is specified in the metadata file.
#
# if use_in_feed is True, then those posts will be added to the site's
# rss feeds.
#
post_pages = (
    ("posts/*.txt", "posts", "post.tmpl", True),
    ("stories/*.txt", "stories", "story.tmpl", False),
)

It will use the first location that has the last parameter set to True, or the last one in the list if all of them have it set to False.

The new_post command supports some options:

$ nikola new_post --help
Usage: nikola new_post [options]

Options:
-h, --help            show this help message and exit
-p, --page            Create a page instead of a blog post.
-t TITLE, --title=TITLE
                        Title for the page/post.
--tags=TAGS           Comma-separated tags for the page/post.
-1                    Create post with embedded metadata (single file
                        format).
-f POST_FORMAT, --format=POST_FORMAT
                        Format for post (rest or markdown)

Teasers

You may not want to show the complete content of your posts either on your index page or in RSS feeds, but to display instead only the beginning of them.

If it's the case, you only need to add a "magical comment" in your post.

In restructuredtext:

.. TEASER_END

In Markdown:

<!-- TEASER_END -->

By default all your RSS feeds will be shortened (they'll contain only teasers) whereas your index page will still show complete posts. You can change this behaviour with your conf.py: INDEX_TEASERS defines whether index page should display the whole contents or only teasers. RSS_TEASERS works the same way for your RSS feeds.

Drafts

If you add a "draft" tag to a post, then it will not be shown in indexes and feeds. It will be compiled, and if you deploy it it will be made available, so use with care.

Creating a Page

Pages are the same as posts, except that:

The default configuration expects the page's metadata and text files to be on the stories folder, but that can be changed (see post_pages option above).

You can create the page's files manually or use the new_post command with the -p option, qhich will place the files in the folder that has use_in_feed set to False.

Redirections

If you need a page to be available in more than one place, you can define redirections in your conf.py:

# A list of redirection tuples, [("foo/from.html", "/bar/to.html")].
#
# A HTML file will be created in output/foo/from.html that redirects
# to the "/bar/to.html" URL. notice that the "from" side MUST be a
# relative URL.
#
# If you don't need any of these, just set to []

REDIRECTIONS = [("index.html", "/weblog/index.html")]

It's better if you can do these using your web server's configuration, but if you can't, this will work.

Configuration

The configuration file is called conf.py and can be used to customize a lot of what Nikola does. Its syntax is python, but if you don't know the language, it still should not be terribly hard to grasp.

The default conf.py you get with Nikola should be fairly complete, and is quite commented, but just in case, here is a full, customized example configuration (the one I use for my site)

Adding Files

Any files you want to be in output/ but are not generated by Nikola (for example, favicon.ico, just put it in files/. Everything there is copied into output by the copy_files task. Remember that you can't have files that collide with files Nikola generates (it will give an error).

Important

Don't put any files manually in output/. Ever. Really. Maybe someday Nikola will just wipe output/ and then you will be sorry. So, please don't do that.

If you want to copy more than one folder of static files into output you can change the FILES_FOLDERS option:

# One or more folders containing files to be copied as-is into the output.
# The format is a dictionary of "source" "relative destination".
# Default is:
# FILES_FOLDERS = {'files': '' }
# Which means copy 'files' into 'output'

Post Processing Filters

You can apply post processing to the files in your site, in order to optimize them or change them in arbitrary ways. For example, you may want to compress all CSS and JS files using yui-compressor.

To do that, you can use the provided helper adding this in your config.py:

from nikola import filters

FILTERS = {
  ".css": [filters.yui_compressor],
  ".js": [filters.yui_compressor],
}

Where filters.yui_compressor is a helper function provided by Nikola. You can replace that with strings describing command lines, or arbitrary python functions.

If there's any specific thing you expect to be generally useful as a filter, contact me and I will add it to the filters library so that more people use it.

Customizing Your Site

There are lots of things you can do to personalize your website, but let's see the easy ones!

Basics

You can assume this needs to be changed:

# Data about this site
BLOG_TITLE = "Demo Site"
BLOG_URL = "http://nikola.ralsina.com.ar"
BLOG_EMAIL = "joe@demo.site"
BLOG_DESCRIPTION = "This is a demo site for Nikola."
CSS tweaking

The default configuration includes a file, themes/default/assets/css/custom.css which is empty. Put your CSS there, for minimal disruption of the provided CSS files.

If you feel tempted to touch other files in assets, you probably will be better off with a custom theme.

Template tweaking
If you really want to change the pages radically, you will want to do a custom theme.
Sidebar

LICENSE is a HTML snippet for things like a CC badge, or whatever you prefer.

The 'sidebar_links' option lets you define what links go in the right-hand sidebar, so you can link to important pages, or to other sites.

The SEARCH_FORM option contains the HTML code for a search form based on duckduckgo.com which should always work, but feel free to change it to something else.

Footer
CONTENT_FOOTER is displayed, small at the bottom of all pages, I use it for the copyright notice.
Analytics
This is probably a misleading name, but the ANALYTICS option lets you define a HTML snippet that will be added at the bottom of body. The main usage is a Google analytics snippet or something similar, but you can really put anything there.

Getting More Themes

There are not so many themes for Nikola. On occasion, I port something I like, and make it available for download. Nikola has a builtin theme download/install mechanism, its install_theme command:

$ nikola install_theme -l
Themes:
-------
blogtxt
readable

$ nikola install_theme -n blogtxt
Downloading: http://nikola.ralsina.com.ar/themes/blogtxt.zip
Extracting: blogtxt into themes

And there you are, you now have themes/blogtxt installed. It's very rudimentary, but it should work in most cases.

If you create a nice theme, please share it! You can post about it on the nikola forum and I will make it available for download.

One other option is to tweak an existing theme using a different color scheme, typography and CSS in general. Nikola provides a bootswatch_theme option to create a custom theme by downloading free CSS files from http://bootswatch.com:

$ nikola bootswatch_theme -n custom_theme -s spruce -p site
Creating 'custom_theme' theme from 'spruce' and 'site'
Downloading:  http://bootswatch.com/spruce/bootstrap.min.css
Downloading:  http://bootswatch.com/spruce/bootstrap.css
Theme created. Change the THEME setting to "custom_theme" to use it.

You can even try what different swatches do on an existing site using their handy bootswatchlet

Play with it, there's cool stuff there. This feature was suggested by clodo.

Deployment

Nikola doesn't really have a concept of deployment. However, if you can specify your deployment procedure as a series of commands, you can put them in the DEPLOY_COMMANDS option, and run them with nikola deploy.

One caveat is that if any command has a % in it, you should double them.

Here is an example, from my own site's deployment script:

DEPLOY_COMMANDS = [
    'rsync -rav --delete output/* ralsina@lateral.netmanagers.com.ar:/srv/www/lateral',
    'rdiff-backup output ~/bartleblog-backup',
    "links -dump 'http://www.twingly.com/ping2?url=lateral.netmanagers.com.ar'",
    'rsync -rav ~/bartleblog-backup/* ralsina@netmanagers.com.ar:bartleblog-backup',
]

Other interesting ideas are using git as a deployment mechanism (or any other VCS for that matter), using lftp mirror or unison, or dropbox, or Ubuntu One. Any way you can think of to copy files from one place to another is good enough.

Comments

While Nikola creates static sites, there is a minimum level of user interaction you are probably expecting: comments.

The default templates contain support for Disqus. All you have to do is register a forum, put its short name in the DISQUS_FORUM option.

Disqus is a good option because:

  1. It doesn't require any server-side software on your site
  2. They offer you a way to export your comments, so you can take them with you if you need to.
  3. It's free.
  4. It's damn nice.

Important

In some cases, when you run the test site, you won't see the comments. That can be fixed by adding the disqus_developer flag to the templates but it's probably more trouble than it's worth.

Image Galleries

To create an image gallery, all you have to do is add a folder inside galleries, and put images there. Nikola will take care of creating thumbnails, index page, etc.

If you click on images on a gallery, you should see a bigger image, thanks to the excellent colorbox

The gallery pages are generated using the gallery.tmpl template, and you can customize it there (you could switch to another lightbox instead of colorbox, change its settings, change the layout, etc.).

The conf.py options affecting gallery pages are these:

# Galleries are folders in galleries/
# Final location of galleries will be output / GALLERY_PATH / gallery_name
GALLERY_PATH = "galleries"
THUMBNAIL_SIZE = 180
MAX_IMAGE_SIZE = 1280
USE_FILENAME_AS_TITLE = True

If you add a file in galleries/gallery_name/index.txt its contents will be converted to HTML and inserted above the images in the gallery page.

If you add some image filenames in galleries/gallery_name/exclude.meta, they will be excluded in the gallery page.

If USE_FILENAME_AS_TITLE is True the filename (parsed as a readable string) is used as the photo caption. If the filename starts with a number, it will be stripped. For example 03_an_amazing_sunrise.jpg will be render as An amazing sunrise.

Here is a demo gallery of historic, public domain Nikola Tesla pictures taken from this site.

Optimizing Your Website

One of the main goals of Nikola is to make your site fast and light. So here are a few tips we have found when setting up Nikola with Apache. If you have more, or different ones, or about other webservers, please share!

  1. Use a speed testing tool. I used Yahoo's YSlow but you can use any of them, and it's probably a good idea to use more than one.

  2. Enable compression in Apache:

    AddOutputFilterByType DEFLATE text/html text/plain text/xml text/css
    
  3. If even after you did the previous step the CSS files are not sent compressed:

    AddType text/css .css
    
  4. The webassets Nikola plugin can drastically decrease the number of CSS and JS files your site fetches.

  5. Through the filters feature, you can run your files through arbitrary commands, so that images are recompressed, Javascript is minimized, etc.

Restructured Text Extensions

Nikola includes support for a few directives that are not part of docutils, but which we think are handy for website development.

Youtube

To link to a youtube video, you need the id of the video. For example, if the URL of the video is http://www.youtube.com/watch?v=8N_tupPBtWQ what you need is 8N_tupPBtWQ

Once you have that, all you need to do is:

.. youtube:: 8N_tupPBtWQ

Vimeo

To link to a vimeo video, you need the id of the video. For example, if the URL of the video is http://www.vimeo.com/20241459 then the id is 20241459

Once you have that, all you need to do is:

.. vimeo:: 20241459

If you are running python 2.6 or later, or have the json module installed and have internet connectivity when generating your site, the height and width of the embedded player will be set to the native height and width of the video. You can override this if you wish:

.. vimeo:: 20241459
    height=240
    width=320

code-block

This is a somewhat complicated directive to display code nicely. You can just embed code like this:

.. code-block:: python

    print "Hello World!"

Or you can include the code from a file:

.. code-block:: python
   :include: /foo/bar/baz.py

listing

To use this, you have to put your source code files inside listings or whatever your LISTINGS_FOLDER variable is set to. Assuming you have a foo.py inside that folder:

.. listing:: foo.py python

Will include the source code from foo.py, highlight its syntax in python mode, and also create a listings/foo.py.html page and the listing will have a title linking to it.

Advanced Code Options

Both code-block and listing support a number of options, including these:

start-at
A string, the diplayed code will start when it finds this
end-at
A string, the diplayed code will end when it finds this
start-after
A string, the diplayed code will start in the line after this
end-before
A string, the diplayed code will end in the line before this
linenos
Display line numbers
linenos_offset
Use the original file's line numbers (warning: broken)
tab-width
Size of the tabs (default 4)

gist

You can easily embed GitHub gists with this directive, like this:

.. gist:: 2395294

Producing this:

System Message: ERROR/3 (docs/manual.txt, line 867)

Unknown directive type "gist".

.. gist:: 2395294

This degrades gracefully if the browser doesn't support javascript.

Slideshows

To create an image slideshow, you can use the slides directive. For example:

.. slides::
   :preload:
   :play: 350

   /galleries/demo/tesla_conducts_lg.jpg
   /galleries/demo/tesla_lightning2_lg.jpg
   /galleries/demo/tesla4_lg.jpg
   /galleries/demo/tesla_lightning1_lg.jpg
   /galleries/demo/tesla_tower1_lg.jpg

This is based on slidejs and it supports the options described there with one minor tweak to make them fit in docutils convention: If the option takes a boolean value, you just have to add it or not. For example, to enable preloading, just use the :preload: option.

If the option takes any other kind of argument, just use it after the option, like play in the above example.

Importing Your Wordpress Site Into Nikola

If you like Nikola, and want to start using it, but you have a Wordpress blog, Nikola supports importing it. Here's the steps to do it:

  1. Get a XML dump of your site [1]
  2. nikola import_wordpress -f mysite.wordpress.2012-12-20.xml

After some time, this will crate a new_site folder with all your data. It currently supports the following:

This feature is a work in progress, and the only way to improve it is to have it used for as many sites as possible and make it work better each time, so I am happy to get requests about it.

[1]

The dump needs to be in 1.2 format. You can check by reading it, it should say xmlns:excerpt="http://wordpress.org/export/1.2/excerpt/" near the top of the file. If it says 1.1 instead of 1.2 you will have to update your wordpress before dumping.

Other versions may or may not work.

Importing To A Custom Location Or Into An Existing Site

It is possible to either import into a location you desire or into an already existing Nikola site. To do so you can specify a location after the dump.:

$ nikola import_wordpress -f mysite.wordpress.2012-12-20.xml -o import_location

With this command Nikola will import into the folder import_location.

If the folder already exists Nikola will not overwrite an existing conf.py. Instead a new file with a timestamp at the end of the filename will be created.

License

Nikola is released under a MIT license which is a free software license. Some components shipped along with Nikola, or required by it are released under other licenses.

If you are not familiar with free software licensing: In general, you should be able to do pretty much anything you want, unless you modify Nikola. If you modify it, and share it with someone else, that someone else should get all your modifications under the same license you got it.