Fast blogging setup

9 years ago

## Static vs Dynamic

I've maintained my own website/blog for as long as i can remember. Ever since the days of static HTML pages, simple PHP scripts, [Wordpress](http://wordpress.org) installations, [Joomla](http://www.joomla.org), [Drupal](https://www.drupal.org), [Postnuke](http://www.postnuke.com), [PHPNuke](https://www.phpnuke.org), you name it, i've tried it.

So one day i found out about static site generators. The basic idea is that, instead of having some kind of storage for the content (database), it lives in plain files. The webpages are generated by an engine and can then be served as plain HTML which is - obviously - much faster than any interpreted system (like PHP, Rails, ).

Here's an example of dynamic page generation like - for instance - a Wordpress installation, or a Ruby on Rails website:

The biggest problem with this is speed. Since there are so many steps, it can never be as efficient as static HTML pages. Of course you can always cache the requests and make it a bit faster, but i tend to like the path of least resistance :)

Here's the static generation approach:

The website pages are generated once and served statically, which is much faster.

Before i proceed to explain how i've implemented it, let me just say that there are many advantages for a full fledged dynamic website (e-commerce, storing user information, registrations, etc, etc.). But if your only concern is to publish content on the web and allowing readers to comment on it you can easily pull it off with this system, integrating it with something like [Disqus](https://disqus.com/websites/), for comments.

## Practical example

To implement this system we need:

- **A static website generator**. I chose [Middleman](http://middlemanapp.com/). Others include [Jekyll](http://jekyllrb.com/), [Hugo](http://hugo.spf13.com/, [Pelican](http://blog.getpelican.com/), [Hexo](http://hexo.io/) and [DocPad](http://docpad.org/). - **Some way to transfer the generated files to your server**. [Rsync](http://en.wikipedia.org/wiki/Rsync) is my choice, but you can pull it off in a gazillion ways, including [Dropbox](https://www.dropbox.com) synchronization, for example, or just FTP. - **A web host running a webserver**. In my case i have a [Linode](http://www.linode.com/) with an [Ubuntu](http://www.ubuntu.com) installation that has [Nginx](http://www.nginx.org/) running. Other solutions might include a combination of [Apache](http://httpd.apache.org/), [Dreamhost](http://www.dreamhost.com/), [HTTP Explorer](http://http-explorer.sourceforge.net/), [Bluehost](http://www.bluehost.com/), [LightHTTPD](http://www.lighttpd.net/) and [A Small Orange](http://www.asmallorange.com/)

### Step 1 : Install Middleman

There are plenty of guides on how to install this out there, so i'll just point you to the [getting started guide](http://middlemanapp.com/basics/getting-started/).

### Step 2 : Create your pages

Middleman has a bunch of templates that you can use as a starting point, so check out their fantastic documentation and make it happen. In alternative you can proceed with the example template you should have ended up with if you followed their tutorial.

### Step 3 : Middleman commands to know

Here are the commands you are most likely to use with middleman, and their explanation:

**Start the development server**, so you can test your site at `http://localhost:4567`:

middleman

**Generate a new blog post**, assuming you installed and set up the [middleman-blog plugin](http://middlemanapp.com/basics/blogging/):

middleman article "title of your new post"

**Build the static pages for deployment**:

middleman build

**Deploy your pages using middleman**:

middleman deploy

### Step 4 : Deploy

You don't necessarily need to use the `middleman deploy` command if you don't want to. After you do `middleman build` all your generated content can be found inside the `build` folder on your project root. Deploying it is simply a matter of getting those files into your webserver. And for that you can use any method you prefer.

I like to let my server do all the work of building and deploying by using the following workflow:

- I write a post or modify a page - I call a script on my local computer that does the following:

#!/bin/sh rsync -h -r --delete /data/static-blog/source/* void@blog:/home/void/static-blog/source ssh void@blog "touch /home/void/static-blog/.build"

First, it copies all of my site's sources into the working folder on the server (this is the step where you could use dropbox, btw). Then it creates a file on that folder (`.build`) that instructs the server to build and deploy the website automatically.

- The server has a cron job running every X minutes that executes a script:

*/5 * * * * /home/void/bin/build_blog.sh

And the contents of that script are:

#!/bin/bash if [ -e "/home/void/static-blog/.build" ] then logger -s "Blog: Starting build..." logger -s "Blog: Sourcing RVM..." source /home/void/.rvm/environments/ruby-2.0.0-p0 logger -s "Blog: Removing order file..." rm /home/void/static-blog/.build logger -s "Blog: Getting into folder..." cd /home/void/static-blog logger -s "Blog: Executing bundle install..." /home/void/.rvm/gems/ruby-2.0.0-p0/bin/bundle install logger -s "Blog: Building files..." /home/void/.rvm/gems/ruby-2.0.0-p0/bin/middleman build logger -s "Blog: Copying files into place..." rsync -h -r --delete build/* /data/static-blog/live/ logger -s "Blog: Build done." fi

Simply put, the script checks for the existence of the `.build` file inside the working folder and - if so - sets up the environment for bundle, generates the website, and moves the generated files in the `build` folder into the nginx folder i have setup in `/data`. It also removes the trigger `.build` file so the process isn't restarted on the next cron execution.

## Conclusion and future work

I think this is an overall nice setup. Things i would like to improve include not having to trigger the build process. Ideally any change to the blog folder on my laptop should automatically build and deploy the website. Reasons why i haven't been able to do it:

- Dropbox doesn't seem to trigger file changes for [incron](http://inotify.aiken.cz/?section=incron&page=about&lang=en) (a file system watch service), which sucks. - [inotify](http://inotify.aiken.cz) is an alternative to incron, but unfortunately i've ran into another problem: Changes in files inside the working folder trigger multiple alarms (sometimes more than one per changed file). This means i have no way of knowing if the file syncronization has ended (either by dropbox or rsync) and wether i can start the build process or not. Otherwise i risk building with only half the files in place and that might break the site.

If you have any ideas on how to make the process more efficient [please share](http://twitter.com/nocivus); i would love to hear all about it.