Skip to main content

Installing FreeBSD on OVH

While OVH has a number of Linux-based options for their low-end VPS offerings, I wanted to try installing FreeBSD. As far as I can tell, OVH doesn't offer the ability to provide a bootable .iso or .img installer image for their VPS offerings (unlike their dedicated server instances). Fortunately, their VPS offers a recovery console with SSH access along with the use of dd, gzip/gunzip, and xz. This grants SSH access to therecovery console to write the disk image directly to the virtual drive which I learned from murf.

The following was all done on a fairly stock FreeBSD 11 install.

My first problem was that the official downloadable .raw hard-drive image was something like 20.1GB which was just slightly larger than my available 20.0GB of space so I couldn't directly write the image provided on the FreeBSD site.

Create a local image file

First I need to create a drive-image file that is the right size.

user@localhost$ dd if=/dev/zero of=$HOME/freebsd.img bs=20m count=1k

This will create a 20gb image file that should fit exactly in the available space on the OVH VPS. If you're using the lowest-end VPS, change that to 10m to make a 10gb drive instead.

Create a device for the file

In order to install to this file as a disk, FreeBSD needs to recognize it. This can be done with the mdconfig command as root.

user@localhost$ su -
Password: ********
# mdconfig -f ~user/freebsd.img -u 0

This will create a md0 device to which FreeBSD can be installed.

Install FreeBSD

With the md0 device created we can run bsdinstall and choose md0 as our target drive.

If your current setup uses ZFS and already has bootpool & zpool pools and you plan to use the automated "Guided root on ZFS" install, you'll need to instruct bsdinstall to use pool names that don't conflict with your existing pools. While the installer gives the ability to change the main pool name, it doesn't give a way to change the name of the boot-pool without setting an environment variable. I recommend just setting them both in the environment for simplicity.

# export ZFSBOOT_POOL_NAME=myzpool
# export ZFSBOOT_BOOT_POOL_NAME=mybootpool
# bsdinstall

For the Keymap Selection, continue with the default keymap unless you have reason not to.

For the hostname, this post uses "ovh".

For your mirror selection, choose something geographically close. I arbitrarily chose one of the Primary FTP sites.

Since my target OVH instance has 4GB of RAM, this guide opts for the "Guided root on ZFS" install option. If I only had the 2GB VPS, I might go with UFS instead.

For options, I use

  • Specify the pool type as a stripe and add the md0 disk to the pool
  • Since I only have 20GB total disk space to work with, I reduce my swap size from the default 2GB down to either 1GB or 512MB
  • I like to specify that my disks are encrypted
  • I leave the partition scheme set to GPT, keep 4K sectors, and don't bother mirroring or encrypting my swap
and yes, I want to destroy the contents of md0 which should just be an empty file.

After the installer fiddles with the disks, partitions, and pools, it will ask which sets you want to install. Again, with only ~20GB of space to use, I strip this down to the basics

Install FreeBSD

# Make note of existing values for # $EXTERNAL_IP # $GATEWAY_IP # $DNS_NAMESERVER # $DNS_SEARCH # if using ZFS on both the host where building the .raw image # and within the image itself # set the pool names so they don't conflict # if you already have pools named "bootpool" and "zpool" export ZFSBOOT_POOL_NAME=ovhzpool export ZFSBOOT_BOOT_POOL_NAME=ovhbootpool bsdinstall # can do a UFS or ZFS # skip networking for now # but do enable sshd and ntpd if you want them # from # for my local install, using a shell to do the disk layout gpart destroy -F md0 gpart create -s gpt md0 gpart add -t freebsd-boot -s 128k -l boot md0 gpart add -t freebsd-zfs -l ${ZFSBOOT_POOL_NAME} -a 1M md0 # optionally add -T to skip passing TRIM commands to the SSD geli init -e AES-XTS -l 128 -s 4096 -b -g gpt/${ZFSBOOT_POOL_NAME} geli attach gpt/${ZFSBOOT_POOL_NAME} zpool create -R /mnt -O canmount=off -O mountpoint=/ -O atime=off -O compression=on ${ZFSBOOT_POOL_NAME} gpt/${ZFSBOOT_POOL_NAME}.eli zfs create -o mountpoint=/ ${ZFSBOOT_POOL_NAME}/ROOT zpool set bootfs=${ZFSBOOT_POOL_NAME}/ROOT ${ZFSBOOT_POOL_NAME} zfs create ${ZFSBOOT_POOL_NAME}/home zfs create -o canmount=off ${ZFSBOOT_POOL_NAME}/usr zfs create ${ZFSBOOT_POOL_NAME}/usr/jails zfs create ${ZFSBOOT_POOL_NAME}/usr/local zfs create ${ZFSBOOT_POOL_NAME}/usr/obj zfs create ${ZFSBOOT_POOL_NAME}/usr/src zfs create ${ZFSBOOT_POOL_NAME}/usr/ports zfs create ${ZFSBOOT_POOL_NAME}/usr/ports/distfiles zfs create -o canmount=off ${ZFSBOOT_POOL_NAME}/var zfs create ${ZFSBOOT_POOL_NAME}/var/log zfs create ${ZFSBOOT_POOL_NAME}/var/tmp zfs create ${ZFSBOOT_POOL_NAME}/tmp # do add a new user that you'll use to log in, # and make sure they're added to the additional group "wheel" # at the end of bsdinstall, enter a shell # edit /etc/rc.conf to add the lines ifconfig_vtnet0="inet $EXTERNAL_IP netmask broadcast $EXTERNAL_IP" static_routes="net1 net2" route_net1="$GATEWAY_IP -interface vtnet0" route_net2="default $GATEWAY_IP " ifconfig_vtnet0_ipv6="inet6 $IPV6ADDR prefixlen 64" ipv6_defaultrouter="$IPV6ROUTE" # if you plan to use jails, don't let syslogd listen on all addresses syslogd_flags="-ss" # and set up a loopback interface to use cloned_interfaces="lo1" # edit /etc/resolv.conf search nameserver # edit /etc/ssh/sshd_config ListenAddress $EXTERNAL_IP PermitRootLogin no # if ZFS unmount all the new ZFS items under /mnt mount | awk '/\/mnt/{print "umount " $3' | sort -r mount | awk '/\/mnt/{print "umount " $3' | sort -r | sh # ZFS still has these pools active so disconnect them zpool export $ZFSBOOT_POOL_NAME zpool export $ZFSBOOT_BOOT_POOL_NAME # if encrypted, detach the GELI devices if needed: geli detach /dev/md0.eli # done making changes so unmount it umount /mnt mdconfig -d -u 0 # gzip it up to save bandwidth (~400MB instead of 20GB or roughly 2%) # keeping it in case we need it again gzip --keep freebsd.img # restart VPS in rescue mode # ssh into your VPS rescue $IP: ssh root@$IP # unmount the drive you'll be writing to root@vps: umount /mnt/vdb1 root@vps: exit # upload the image to the drive ssh root@$IP "gunzip | dd of=/dev/vdb bs=1M" < freebsd.img.gz

Unsorted ed(1) Tips and Tricks

Edit text like a pro with ed(1)

I came across Ten unsorted vi/vim tricks, volumes one & Ten unsorted vi/vim tricks, volume two and thought I'd compile a similar list for ed(1).

In this post I will present counterpoints with easy & but useful tricks using ed(1) commands and, in the Unix philosophy, external tools.

You might ask, why ed(1)?

  • ed(1) is always* there. Since ed(1) is required by POSIX, you should find it in any *nix/Linux distribution. Well, it should be there. Sadly, many distros are now dropping ed(1) from their core installations, making it an optional add-on package.
  • ed(1) is small but mighty. On various systems at my disposal, ed(1) clocks in at between 51k and 183k, while nano is 2-4x as large, vi/vim is 3-20x as large, and emacs clocks in at over 8 megs. Yet ed(1) provides a lot of functionality in those meager few bytes.
  • ed(1) needs no configuration. You don't have to worry about sitting down at a foreign machine and now knowing how ed(1) is configured. Yes, there are some subtle differences between GNU ed(1) and BSD ed(1) but the vast majority is the same.

Getting some help

ed(1) is known for its terse "?" reply to any issue. You can request in-line help with the "h" command for a bit of a hint. Additionally, the man page should cover everything you need to know.

No match

Search and replace

To search, use the "/" or "?" command followed by your search pattern.

18 this line contains "pattern"

To search and replace on the current line, use the "s" command:

or, apply the changes over a range:

Show line numbers

To show line numbers in ed(1) add the suffix "n" to your command, for example


Execute an external command from within ed(1)

Use the "!" command to execute


Insert an existing file into the current one

In case you need to insert the contents of a file into the one you're currently writing, use the "r" command.

r file.txt
Note that ed(1) lets you know how many bytes were added to your file.

Display changes performed since last save

This trick uses diff to display the difference between the file on disk and the current editing buffer.

w !diff -u file.txt -

Indendent and un-indenting lines

To indent a range of lines, substitute the beginning of the line with either spaces or tabs:

12,18s/^/    /
To unindent, strip off that number of leading indentation:
12,18s/^    //
12,18s/^ \{4\}//

Undo & redo

ed(1) provides one level of undo/redo, using the "u" command to toggle between them:

$ ed
1 hello
1 hello
2 world
1 hello

Insert the output of an external command

Similar to the insertion of a file above, ed(1) lets you use the "r !" command to read the output of an external program:

r !ls -l

Record commands

Command history

Since ed(1) appends to the terminal window rather than overwriting and redrawing the screen, the entire editing history for the given ed(1) session is available for review.

Using ed(1) as a password manager

I recently came across a post on using vim as a password manager so I thought I'd post a companion article on using ed(1) as a password manager.

The main goal is to be able to keep the secrets encrypted at all times on disk, only decrypting within the active ed(1) session.

BSD ed(1) offers an x command (well, OpenBSD removed it in revision 1.37 of /src/bin/ed/main.c "because DES") that allows for weak DES encryption of the file. However, we want stronger encryption and portability between various versions of ed(1) so will ignore this option.

Writing our encrypted password file to disk

To begin, we'll open up ed(1) and add some password content

user@hostname$ ed
Username: demo
Password: Pa$$w0rd1

Password: ed(1)uc8


Now, instead of writing the unencrypted password file, we'll use gnupg to encrypt the file and write it out to the disk by piping the file through gpg instructing it to write to our password file. Note the trailing "-" which tells gpg to read the input from stdin. gpg will prompt for a passphrase and confirmation of that password.

w !gpg --symmetric --output passwords.gpg -
Enter passphrase: Password1
Repeat passphrase: Password1

ed(1) informs us that it successfully piped our 127 bytes of data through gpg but we can confirm that the passwords.gpg file was written and then we can quit to go about our day:

!ls passwords.gpg

Reading our encrypted password file from disk

Now, we want to be able to look up a password to enter at some future point. So we fire up ed(1) and decrypt our passwords.

user@hostname$ ed
r !gpg --decrypt passwords.gpg
Enter passphrase: Password1

We want to look up our log-in credentials for our email server so we issue

Password: ed(1)uc8

(Yes, using "+" can be replaced with just hitting "<Enter>") Alternatively, we could use grep(1) or sed(1) to filter the results and show some context:

user@hostname$ gpg --decrypt passwords.gpg | grep -A2
Enter passphrase: Password1
Username: demo
Password: Pa$$w0rd1
user@hostname$ gpg --decrypt passwords.gpg | sed -n '/,/^$/p'
Enter passphrase: Password1
Username: demo
Password: Pa$$w0rd1

Modifying our password lists

Now we want to modify our document and/or change our master-password:

user@hostname$ ed
r !gpg --decrypt passwords.gpg
Enter passphrase: Password1
Password: Pbuttwrd1
Username: ed1conf
Password: EyeDonutThinkSew

w !gpg --symmetric --output passwords.gpg -
Enter passphrase: NewPassword2
Repeat passphrase: NewPassword2
File `passwords.gpg` exists. Overwrite? (y/N) y

And there you have it: using ed(1) as a password manager.

Why ed(1)?

As the weirdo behind the somewhat tongue-in-cheek @ed1conf account I'm occasionally asked "Why ed(1)?" Hopefully some of my reasons for learning & using ed(1) can pique your interest in taking the time to get to know this little piece of history.


Sometimes your favorite $EDITOR is installed, sometimes it's not. Some, like vi/vim are just about everywhere. Other times, you would have to have sufficient privileges/space to install or compile your editor of choice. But if you know ed, nearly every Linux/BSD/Mac has it installed because it's part of the POSIX standard. It's even small enough to fit on most recovery media without breaking the bank. But between ed and vi/vim, I know that I can get things done even when I'm on a new machine.

Sometimes it's the only editor you have

Several times in my life ed has been the only editor available in certain environments.

  • At $DAYJOB[-1] the Linux-based router needed some configuration changes that the web interface didn't accommodate. So a quick terminal connection later (telnet, sigh), I discovered that ed was the only editor available. No problem. Edited the config file and we were back up and running with the proper changes.
  • At the same $DAYJOB[-1], I developed software for a ruggedized hand-held device and its attached printer. This was back when PDAs were just becoming popular, so this thing was a brick. The DOS-based operating system had no built-in editor, meaning editing files usually meant laboriously copying the file over a serial link to the PC, editing it there, then sending it back down. I longed for the ability to cut that time down but very few of the full-screen editors I tried were even able to successfully paint on the small LCD screen-buffer properly, and of those that did, the on-screen keyboard took up so much screen real-estate as to make them useless. So I installed a DOS build of ed and it worked like a charm (better than edlin.exe that I also tried). Editing turn-around and testing went from 15-20 minutes down to 3-5 minutes per iteration.
  • Some platforms such as Heroku provide only ed as their editor. Not usually an issue since most of the time you're not trying to edit live on the server. But if you need to do it, it's nice to know how.
  • On some MUD games and old BBSes, the text-editor is often an ed-like editor.

Visible editing history

Unless you have a key-echoing utility like Screenkey or Screenflick, it's hard for an audience to see exactly what you did when you're editing during a presentation. It's nice to for the audience to be able to see exactly what you typed if they're trying to follow along.

All commands are ASCII text

Sometimes your terminal emulator or keyboard isn't configured correctly. Function keys, arrows, alt- and meta-modifiers may not transmit properly. Since all of ed's commands are basic ASCII, it works even if your keyboard/terminal is unable to send extended characters properly.

It works when $TERM is messed up

Likewise, your $TERM setting can get messed up. Sometimes full-screen terminal applications leave the screen in a state where everything is somewhat garbled. Yes, there's reset which will let you reset the terminal back to some sensible defaults, but sometimes your termcap database has trouble too. An editor that only uses stdin and stdout can save your bacon.


Because ed reads all of its commands from stdin and writes all output to stdout in a serial fashion, it's very usable in a screen-reader like yasr or speakup allowing you to edit text without a screen. If you've never edited text sightless, give it a try some time.


Because ed reads all of its commands from stdin it's easy to write a script that will edit a file in an automated fashion.

Previous output

On occasion, I want to see the output of one or more previous shell commands while I continue to edit. A full-screen editor takes over the entire screen, preventing me from seeing that output. With ed the previous output is right there and remains in my scroll-back buffer for reference while I edit. I find this particularly useful when using \e in psql or mysql if my $EDITOR is set to ed. This allows me to edit the SQL while keeping the results of my previous query visible.

Small, fast, light

On resource-constrained systems, sometimes you need something light like ed where the executable and memory-footprint are measured in kilobytes rather than megabytes. This is less of a problem on most systems these days, but with small resource-constrained SOC and embedded boards running Linux or BSD, a light-weight yet powerful editor can help.

Usable on low-bandwidth/high-latency connections

Sometimes you are connected by a slow or very laggy connection. Whether this is a satellite uplink, a 300-baud serial connection, or a congested WAN link, sometimes you simply want to edit productively without the overhead of repainting the screen.

Showing off

Finally, there's a small measure of grey-beard prestige that comes with using an editor that baffles so many people. It's a fast way to demonstrate that I'm not some newbie with cert-only knowledge, but that I enjoy Unix history and working at the command-line. Or maybe it shows that I'm just a little crazy.

Software for a command-line world

Below are a list of programs that can all be used over an SSH connection with no need for an X connection.

  • mail (command-line; uses local mailboxes)
  • mutt (full-screen; uses local mailboxes, POP3, or IMAP)
  • elm (full-screen; uses local mailboxes, may support POP3/IMAP)
  • mh/nmh (mail-handler/new-mail-handler; command-line; uses "MH" format, supports POP3 via fetchmail)
  • pine/alpine (full-screen; uses local mailboxes, POP3, or IMAP)
  • offlineimap
  • and many others
  • lynx (the classic full-screen text-browser)
  • links/links2 (a full-screen text-browser with more visual layout engine)
  • elinks (a full-screen text-browser with more visual layout engine)
  • w3m
  • edbrowse (it's an editor, it's a browser, it's command-line)
Text Editing:
  • vi/vim (the classic full-screen text-editor)
  • emacs (another popular and extensible choice in full-screen text-editors)
  • ed (the classic command-line text editor)
  • nano (a simple full-screen editor)
  • pico (a simple full-screen editor)
  • edbrowse (it's like ed on steroids)
  • and countless others

these can be used in concert with various markup syntax such as Markdown, HTML, DocBook, LaTeX, etc to produce publishable documents; you can use packages like antiword or wordview ("wv") to convert .DOC files to a usable format.

  • Spreadsheet:
    • sc (a simple full-screen spreadsheet with vi-like keybindings)
    • sc-im (like sc above but with the ability to import/export xls/xlsx files)
    • slsc (based on sc)
    • oleo (a simple full-screen spreadsheet with a more Emacs-like feel)
  • Math:
  • Graphing:
  • Calculator
    • bc (a simple command-line calculator)
    • python (the full power of Python, at a command-line)
  • calendar (show events on given days)
  • remind (like the previous calendar program on steroids)
  • cal (display a calendar)
  • pcal (good for printing)
  • cron (for scheduling repeated tasks)
  • at (for scheduling a single job sometime in the future)
  • gcalcli (interact with Google Calendar from the command-line)
  • khal
  • mencal and mencal2 (menstruation calendars)
To-do/time management:
TimeTracker (a simple command-line time-tracker in the spirit of many VCS tools, written by yours-truely in response to this post, and somewhat documented here)
  • finch (a console version of Gaim/Pidgin)
  • centericq (support for ICQ, Yahoo!, AIM, IRC, MSN, Gadu-Gadu and Jabber protocols)
  • naim (support for AIM, ICQ, IRC, and the lily CMC protocols)
  • irssi (popular IRC client)
  • weechat
  • gtmess (MSN client)
  • psql interface to PostgreSQL
  • mysql interface to MySQL
  • sqlite interface to the sqlite database
  • all the major databases have command-line clients
Version control:
I currently use git, Mercurial, Bazaar, Subversion and RCS depending on the project context
  • top, ps, kill, who, last
  • ping, traceroute, dig, ifconfig, ip, netstat, nslookup
  • openssl, ssh, sftp, scp, rsync
  • iotop an I/O monitor like "top"
  • weather

I also find that using "tmux" or GNU "screen" vital to being productive, as I can do many, many things all at the same time, each in their own window. It also allows me to disconnect and then reconnect from another machine later, resuming where I left off.

Installing & Configuring Nikola


This assumes that you have installed which isolates this installation from other projects you may have installed locally.

Create a virtual environment

bash$ mkvirtualenv myenv
This command creates a new virtual environment named "myenv". You can choose any name you like as long as it makes sense to you. Because I use this virtual environment for Nikola, I unimaginatively call mine "nikola". Once the command has completed, virtualenvwrapper automatically puts you in that virtual environment as shown by the prefix "(myenv)".

Optionally integrating shell completion

Adding shell completion is optional, but a nice addition that Nikola provides. The following two commands enable Nikola-specific tab-completion when you activate your virtual environment, and disable it when you deactivate the virtual environment.

(myenv)bash$ nikola tabcompletion --shell bash --hardcode-tasks >> "${VIRTUAL_ENV}/bin/postactivate"
(myenv)bash$ echo "complete -r nikola" >> "${VIRTUAL_ENV}/bin/predeactivate"

If you use zsh instead of bash, you can specify "--shell zsh" instead of "--shell bash".

Deactivating the virtual environment

(myenv)bash$ deactivate
This exits the virtual environment you created. Alternatively, you can just quit your command shell using "exit". During initial setup, you can skip this step, as you'll just need to reactivate the virtual environment to install Nikola.

Reactivating the virtual environment

bash$ workon myenv
This will activate the "myenv" environment again, as well as put the environment-name indicator in your prompt. If you didn't deactivate the virtual environment using deactivate, then you won't need to reactivate your virtual environment.

Install Nikola

(myenv)bash$ pip install Nikola
Inside your virtual environment (as shown by the environment-name inside parentheses before your usual prompt), this uses pip to fetch the latest version of Nikola and install it. This brings in a number of dependencies, some of which may need to be compiled. As such, if you don't have a compiler installed on your machine, you'll want to do that before this step.

Create a new blog

(myenv)bash$ cd /path/to/your/blog
(myenv)bash$ nikola init myblog
You can choose a name that you like for the folder instead of "myblog" (or similarly boring reasons, I named mine "blog"). This creates a folder called /path/to/your/blog/myblog in which your content, templates, cache, and output will go. It also prompts you for the name of your site, the main author's name, the main author's email address, a description of the site, the root URL for the site (which should end with a trailing slash such as ""), the languages you intend to use, your time zone, and which comment system you want to use (if any).


Nikola's configuration takes place in "/path/to/your/blog/myblog/". Opening this file in your favorite text editor, you'll notice that the answers you gave during the "nikola init" process appear as the values to various settings within this file.

By default, Nikola expects markup to be reST but I prefer the straight-forward nature of HTML. So my first stop was to add HTML as a processed language. By putting it first in the list, it becomes the default for new_post which saves me from forgetting to specify the template as "-f html" every time I generate a new post. To do this, I modified the "POSTS = (…)" and "PAGES = (…)" to include the following lines:

    ("posts/*.html", "posts", "post.tmpl"),
    ("posts/*.rst", "posts", "post.tmpl"),
    ("posts/*.txt", "posts", "post.tmpl"),
    ("stories/*.html", "posts", "post.tmpl"),
    ("stories/*.rst", "stories", "story.tmpl"),
    ("stories/*.txt", "stories", "story.tmpl"),

I want to have my templates contain additional metadata fields for author (allowing me to easily override this for guest posts) and category. To do this, I found the comment containing ADDITIONAL_METADATA and added the following lines:

    "author": BLOG_AUTHOR, # default to me
    "category": "uncategorized",

I also customized the CONTENT_FOOTER to show a minimal copyright notice:

    Contents © {date}
    <a href="mailto:{email}">{author}</a>

To round out some personal preferences, I explored the Nikola handbook and added the following settings in their respective places:

SOCIAL_BUTTONS_CODE = "" # I don't want social buttons
COPY_SOURCES = SHOW_SOURCELINK = False # not very useful with HTML fragments
USE_BUNDLES = False # may change this later

Finally, I wanted to enable automated deployment of my blog to my web-hosting service. To deploy without needing to enter the password for my hosting service, I set up SSH keys and used ssh-copy-id to push the public key up to my server. With that in place, I adjusted the (formerly empty) list of commands DEPLOY_COMMANDS .

    "rsync -avr --delete output/ {login}@{host}:{path}".format(

This allows me to deploy by simply issuing "nikola deploy".

With Nikola installed and configured to my liking, it's time to go write some blog posts.

Why Nikola?

Why a static site generator over a dynamic blog engine?

  • I prefer to work in raw HTML because I've been doing it for years, and the markup is readable. For some reason, Markdown, Textile, and reST drive me nuts—mostly because it's easy for me to enter things I don't intend as markup, and when I want to do complex markup, I have to look up the obscure syntax in the documentation. Every. Single. Time.

    Most of the blogging engines (such as Wordpress and Drupal ) do allow for directly entering raw HTML, but it always feels like I'm fighting against the grain. Every time I go to compose a post, I have to toggle into a special "HTML entry" mode. One wrong turn and some of the engines will "sanitize" my HTML, reformatting everything. A blogging engine should treat my content as sacred and never try to second-guess (or reformat) what I want.

  • To deploy these dynamic blog engines, it requires a server with the ability to run code (usually PHP but some used mod_perl, mod_python, or mod_cgibin) and a backing database such as MySQL. Granted, you can find free and low-cost hosting that provides simple PHP/MySQL access, so this isn't a huge hurdle, but it does place additional restrictions on which services you can use.
  • Some of the cheap/free shared-hosting plans put so many hosts co-located on the same hardware that performance becomes an issue—both database processing and the engine's processing. With a static site generator, there is very little overhead in serving static pages.
  • The more dynamic components in play, the more likely it is that vulnerabilities lurk due to the extra exposure. With a static site, far fewer parts are in motion to be attacked so I don't worry about vulnerabilities in PHP, Wordpress, or MySQL.
  • Many of the blog engines don't support versioning of the content. I can keep my static site content under revision control with git, Mercurial, Subversion, or a multitude of others.

Why Nikola rather than the other static site generators?

I compared several static site generators, both using a static site generator comparison site and my own testing. Top contenders included the following:

As I tested them, I started to develop a list of criteria that mattered to me:

  • As a Python developer, I had a bias towards those built in Python. It allows me to poke around under the hood, create patches when I find things I want to change, and gain a deeper understanding of how things worked in the event I hit edge cases.
  • Documentation mattered. Several projects had documentation that was incomplete, hard to navigate, or required JavaScript (which prevented the docs from working nicely on one of my e-readers).
  • Additionally, some projects seem less than active in their development. According to the static site generator comparison site, some hadn't been updated in months or years while others have had sustained, ongoing development.
  • Most importantly, I wanted the ability to compose in HTML fragments rather than being forced to use Markdown, Textile, or reST.
  • So I ended up settling on Nikola as it's developed in Python, allows me to use HTML fragments, has thorough documentation, and is actively developed.

Getting started with blogging


I've long had an interest in starting up a simple blog for the purpose of documenting various projects on which I'm working. So it seems that the first thing I should blog about is the process of choosing and configuring blogging software.

Hand-coded HTML

I started posting things on the web when I was in college where every page was hand-crafted HTML and dumped in ~/public_html/ of my account on the Computer Science web server (I believe it started as a DEC ULTRIX, but then became a Red Hat box) and everything went live thanks to Apache running mod_userdir. Even before using HTML, I frequently used WordPerfect 5.1's "Reveal Codes" ability to inspect the control tags/codes used by the document which saved me much grief. I still prefer HTML over modern markup competitors like Markdown, Textile, or reST because HTML's tags are consistent. When trying the other markup languages, I frequently get stung by entering text that turns out to mean something to the markup engine, and when I reach for some of the more powerful features (tables, acronyms, code blocks, etc), I have to go to the reference materials every single time to make sure I get it correct. In HTML, all markup consists of an opening < followed by a closing >, and entities are always escaped with &. Consistent—the way I like it.

However, any time I wanted to change the look and feel of the site, I had to touch every single file (at least those that I cared about) and I also had to remember to update any index pages every time I added or renamed a page.

Server Side Includes

At some point, I explored using Server side includes to make the site look more uniform. While it was a bit of a hassle, it had the advantage that I could update the look of the site by changing a couple included files. I still had to manually update indexes, but it was a step in the right direction. Again, for deployment, since my college server was running Apache with mod_include installed,

Dynamic blogging platforms

Then blogging platforms such as Wordpress and Drupal came along with dynamic sites backed by a database. These held a lot more promise, allowing me to maintain my content and site theme independently.

Static Site Generators

Finally, static site generators have grown in popularity. They allow for lower server demands, a smaller attack-surface, and a separation of the content from the structure it populates and its . This site has been created with Nikola, a static site generator developed in Python.