Free Static Sites with Middleman and GitHub

By Benjamin Tan Wei Hao

I am going to teach you how to build a website using a new workflow that I have been using to build my own personal landing page, product page, and blog. Not only can you customise your site to fit your every whim and fancy, but I am going to show you how you can do it for free.

We are going to learn how to use Middleman to develop the site, and GitHub to host it. Let’s get started!

What is a Static Site?

A static site does not have any dynamic content. Great examples of static sites are blogs, landing pages and product pages. Since a static site comes “as-is”, it is extremely fast.

Meet Middleman, the Static Site Generator

Middleman bills itself as a “static site generator using all the shortcuts and tools in modern web development.” What exactly is a static site generator? It means that Middleman has scripts that take your source files (written in Markdown) and converts them into HTML. It also contains scripts that will deploy the generated HTML.

Setting Up Middleman and GitHub

Let’s hit the ground running. In this section, we will install Middleman, and learn how to deploy the newly generated site to GitHub. This section also assumes that you have a GitHub account. If not, you should create one.

Installing Middleman

Middleman is written in Ruby, and comes neatly packaged in a gem. Go ahead and fire your terminal, and install the gem:

$ gem install middleman
Successfully installed middleman-3.3.7
1 gem installed

Since we are building a blog, go ahead and install the middleman-blog gem too:

$ gem install middleman-blog
Successfully installed middleman-blog-3.5.3
1 gem installed

Creating a Middleman-powered blog

Assuming you have created a GitHub account, now you can create your very first Middleman project. For this example, my GitHub user name is middleman-ninja. Therefore, I will name my project

% middleman init --template=blog

         run  bundle install from "."
Fetching gem metadata from
Fetching additional metadata from
Resolving dependencies...
Your bundle is complete!
Use `bundle show [gemname]` to see where a bundled gem is   installed.

Middleman will create a Gemfile and run bundle install to install the necessary dependencies. More importantly, it generates the files necessary to create a blog.

Running the Middleman Server

Middleman comes packaged with a server. This allows us to preview the site or a blog post, which is especially useful during development. We haven’t done any coding yet, but as a sanity check, cd into the Middleman project and launch the server:

% cd
% middleman server
middleman server
WARN: Unresolved specs during Gem::Specification.reset:
      rack (< 2.0, >= 1.4.5)
      uber (~> 0.0.4)
      rack-test (~> 0.6.2)
      thor (< 2.0, >= 0.15.2)
      activesupport (>= 3.1, ~> 4.1.0)
      listen (< 3.0, >= 2.7.9)
WARN: Clearing out unresolved specs.
Please report a bug if this causes problems.
== The Middleman is loading
== The Middleman is standing watch at
== Inspect your site configuration at

Point your browser to If you are having troubles, try http://localhost:4567 instead.

If you see the above page, you have successfully set up Middleman. As you can see, Middleman makes no attempt to style your pages. Everything is up to you.

Directory Structure

The structure that Middleman uses is simple:

|-- Gemfile
|-- Gemfile.lock
|-- config.rb
|-- source
    |-- 2012-01-01-example-article.html.markdown
    |-- calendar.html.erb
    |-- feed.xml.builder
    |-- images
    |-- index.html.erb
    |-- javascripts
    |-- layout.erb
    |-- stylesheets
    |-- tag.html.erb

Most of the action is contained in the source directory. Images, CSS stylesheets, and JavaScript are all stored in their respective folders. Posts, or articles as Middleman calls them, are also stored in the source folder. Configuration is done in the config.rb file.

Creating an Article

You can create an article using middleman article "TITLE-GOES-HERE". In the Middleman project root folder, run the following:

% middleman article "5000 killer Middleman Tips"
==> create  source/2015-01-27-5000-killer-middleman-tips.html.markdown

Refresh your browser and you should find the article listed.

Middleman Extensions

We need to pull in a couple more gems in order to build a blog with Middleman and handle deploying to GitHub. Crack open the Gemfile, and make sure it looks like this:

source ''

gem "middleman", "~> 3.3.7"
gem "middleman-blog", "~> 3.5.3"
gem "middleman-deploy", "~> 1.0"

gem "builder", "~> 3.0"

Don’t forget to install the dependencies:

% bundle install

middleman-blog and middleman-deploy are examples of Middleman extensions. Extensions in Middleman need to be activated. This is done in the config.rb file. You will notice that blog has already been activated:

activate :blog do |blog|
  # blog configuration

Configuring Deploy

Right below this, you will need to activate a few other extensions:

activate :deploy do |deploy|
  deploy.method = :git
  deploy.branch = 'master'
  deploy.build_before = true

activate :directory_indexes

Setting Up Git

Before setting up GitHub, initialize a new repository in our project:

% git init

The statically generated files will be on the master branch. This means that you shouldn’t make changes on the master branch. Therefore, let’s create another branch called source:

% git checkout -b source
% git commit -am "Initial commit"
% git push --set-upstream origin source

Once git has done pushing, head over to the repository in GitHub. You will now notice that the source branch has been created.

Setting Up Github

Assuming your GitHub account, create a repository called, where is your GitHub username. Therefore, I will create a new repository called

Following GitHub’s instructions, add the remote repository to your project. Note that we are not doing git push -u origin master yet.

git remote add origin

Now, you can deploy straight to GitHub using the middleman deploy command:

% middleman deploy
         run  middleman build from "."
      create  build/2012/01/01/example-article.html
      create  build/2015/01/27/5000-killer-middleman-tips.html
      create  build/feed.xml
      create  build/index.html
      create  build/tags/example.html
      create  build/2015.html
      create  build/2015/01.html
      create  build/2015/01/27.html
      create  build/2012.html
      create  build/2012/01.html
      create  build/2012/01/01.html
Deploying via git to remote="origin" and branch="master"
Switched to a new branch 'master'
[master (root-commit) fce6394] Automated commit at 2015-01-27 09:55:04 UTC by middleman-deploy 1.0.0
 11 files changed, 451 insertions(+)
 create mode 100644 2012.html
 create mode 100644 2012/01.html
 create mode 100644 2012/01/01.html
 create mode 100644 2012/01/01/example-article.html
 create mode 100644 2015.html
 create mode 100644 2015/01.html
 create mode 100644 2015/01/27.html
 create mode 100644 2015/01/27/5000-killer-middleman-tips.html
 create mode 100644 feed.xml
 create mode 100644 index.html
 create mode 100644 tags/example.html

We have configured the middleman-deploy extension to always build the site (generate the static files) before pushing it to GitHub.

Along the way, GitHub might prompt you for your user name and password:

Username for '': middleman-ninja
Password for '':
Counting objects: 20, done.
Delta compression using up to 4 threads.
Compressing objects: 100% (18/18), done.
Writing objects: 100% (20/20), 2.25 KiB | 0 bytes/s, done.
Total 20 (delta 9), reused 0 (delta 0)
 * [new branch]      master -> master

Note that if you have your SSH keys in GitHub, then you won’t be prompted for your credentials. Give it a few moments, but very soon, your site will be deployed to

Success! You have a fully functioning (albeit ugly) blog hosted completely for free on GitHub!

The Middleman Workflow

As a recap, here’s the workflow:

  1. First, your create a new blog post using middleman article "TITLE".
  2. Second, you write your post.
  3. Third, you deploy to GitHub using middleman deploy.

That’s it! These are the only steps needed when creating a blog post.

Setting Up a Domain Name

What if I wanted the site to point to You have to do two things. First, set up your domain name servers to point to GitHub. This is covered in GitHub.

Second, create a CNAME file. It is extremely important that you create the CNAME file in the source branch because the files in the master branch are clobbered each time you run middleman deploy. Once you are in the branch, create the CNAME file in the source directory.

% git checkout source
% vim source/CNAME

The CNAME file will only contain a single line containing your domain name (without the “www”). For example:

% cat source/CNAME

If you have set up everything right, you will be able to access your site soon.

Bonus! Setting up more than one Middleman site on GitHub

What if you wanted more than one site on GitHub? How would you do that? The setup is slightly trickier, but not all that complicated. The steps are mostly the same, except when it comes to setting up of git branches.

Here’s the plan: We will:

  • start a fresh Middleman project and the same Gemfile to get things started faster
  • set up git
  • configure the middleman-deploy extension in config.rb
  • deploy the site to GitHub

Start a fresh Middleman project

This time, we can give it any name we want. In a fresh directory (do not run this command in the existing ` folder), create a new Middleman blog:

% middleman init middleman-is-awesome --template=blog

Let’s set up the source branch:

% cd middleman-is-awesome
% git init
% git checkout -b source

Open up the Gemfile, and make sure it looks like the following:

# If you have OpenSSL installed, we recommend updating
# the following line to use "https"
source ''

gem "middleman", "~> 3.3.7"
gem "middleman-blog", "~> 3.5.3"
gem "middleman-deploy", "~> 1.0"

# For feed.xml.builder
gem "builder", "~> 3.0"

Remember to install the gems using bundle install:

% bundle install

Now, in config.rb, we need to activate the middleman-deploy extension:

activate :deploy do |deploy|
  deploy.method = :git
  deploy.branch = 'gh-pages'
  deploy.build_before = true

Notice that this time, the deploy.branch is set to gh-pages.

Next, create a new repository in GitHub. For convenience sake, give it the same name. Remember to set the remote too:

% git remote add origin

Once that’s done, you can go ahead and run the deploy command:

% middleman deploy

In a few moments, the newly created site will be available at What about domain names? It is the same story as before. Create a CNAME file in the source directory of the source branch, and point your name servers to GitHub, and you’re set.

Go Forth and Create!

Hopefully, you now realize that Middleman along with GitHub is an extremely potent and cost-effective combination to create static websites. I have found Middleman to have a pleasant workflow. Extensions are available either in the form of Middleman extensions, or as Ruby gems.

This post didn’t cover customising the look and feel. That’s because it is no different from developing and styling any other site! For inspiration, you can look at other sites that were developed using Middleman. Thanks for reading!


Very interesting. I created an alternative way for building static web sites by using client side render of markdown files.


Benjamin, can you tell us why Middleman is better than other static site generators, such as Jekyll (the original, I think), or Octopus? I think there are more variants, but these two come to mind.


Interesting article. You seem to assume that every one has Ruby already installed as you start out with gem installs. You might want a paragraph on installing Ruby, Apache etc. I know that a lot of SitePoint users already know how to do this or have already done it. Maybe a link to "How to install Ruby and Apache" would be enough.



Thanks! However, I think the article being on the SitePoint Ruby channel should be a given that Ruby is installed.


This article done by David Turnbull provides a great run down of other static site generators, and includes Middleman in it. I didn't want to repeat it on this article.


@benjamintanweihao Thanks for the post- I found this helpful.

One possible clarification:

When you say: git push --set-upstream origin source, I receive an error.

I had to create the repo on GitHub first, and then add the remote before I could run this command.

Because We Like You
Free Ebooks!

Grab SitePoint's top 10 web dev and design ebooks, completely free!

Get the latest in Ruby, once a week, for free.