Content Management Systems nowdays are relatively easy to setup and install but usually overkill for static websites like many of the personal blogs. I prefer an alternative, Hugo to generate static site, GitHub Pages for version control and hosting, and Drone.io for auto deployment.

Read below to find out how one can build a static blog/website blazingly fast using these tools.

1. Build a static blog locally

Static web pages are delivered to user exactly as stored unlike dynamic web pages which include web server processing for every request, for example, getting data from database, embedding it in configured templates and generating a HTML page to deliver to user. Absense of such processing makes static websites faster and more reliable.

Here’s a very good introduction to static site generators. Also, read why static website generators are the next big thing.

There are several static site generators today. I like Hugo which is written in Go (we don’t need to know Go programming to use it). Let’s build a blog from scratch using Hugo.

  • Install Hugo from Downloads section of latest release. Successful installation will enable hugo command. Try below to check version.

    $ hugo version
    Hugo Static Site Generator v0.16 BuildDate: 2016-06-12T07:00:35-04:00
    
  • Create a blog in your home directory.

    $ cd $HOME
    $ hugo new site myblog
    

    It will create a directory myblog with below structure.

    myblog
    |-- archetypes
    |-- config.toml
    |-- content
    |-- data
    |-- layouts
    |-- static
    `-- themes
    6 directories, 1 file
    
  • Write first post. Hugo natively supports Markdown, which is super easy format to write our blog posts. Create a post using below command.

    $ cd myblog
    $ hugo new post/first.md
    /home/pradip/myblog/content/post/first.md created
    

    It puts all our posts in content directory (created post directory since we used it in command). Hugo uses TOML as default language for configuration and post’s metadata aka front matter (supports YAML, JSON as well). For example, it added date, draft and title tags in front matter for first post we just created. We can create custom front matter by creating an archetype.

    $ cat /home/pradip/myblog/content/post/first.md
    +++
    date = "2016-07-23T19:46:34-04:00"
    draft = true
    title = "first"
    
    +++
    

    Let’s add some content to our post, say Hello, World ! after +++ at end.

  • Add a theme Hugo has many themes ready to use. We will use hugo-uno. Clone it’s git repository in themes directory.

    $ git clone https://github.com/fredrikloch/hugo-uno.git themes/hugo-uno
    Cloning into 'themes/hugo-uno'...
    remote: Counting objects: 517, done.
    remote: Total 517 (delta 0), reused 0 (delta 0), pack-reused 517
    Receiving objects: 100% (517/517), 3.75 MiB | 2.21 MiB/s, done.
    Resolving deltas: 100% (249/249), done.
    Checking connectivity... done.
    
  • Update configuration config.toml contains configuration for our site which can be overridden as we need. Default configuration looks like,

    $ cat config.toml
    baseurl = "http://replace-this-with-your-hugo-site.com/"
    languageCode = "en-us"
    title = "My New Hugo Site"
    

    Add theme name at end theme = "hugo-uno".

  • Generate static site As we are ready with configuration and our first post, let’s generate site and see how does it look.

    $ hugo --buildDrafts
    Started building site
    1 of 1 draft rendered
    0 future content
    1 pages created
    0 non-page files copied
    0 paginator pages created
    0 tags created
    0 categories created
    in 86 ms
    

    --buildDrafts is needed to compile draft posts (i.e. posts which have draft = 'true' in their front matter). It generates our site and puts it public directory.

    myblog
    |-- archetypes
    |-- config.toml
    |-- content
    |-- data
    |-- layouts
    |-- public
    |-- static
    `-- themes
    
    7 directories, 1 file
    
  • Preview our blog on local machine Hugo provides its own webserver which builds and serves the site. Let’s start server for our blog by executing below commnd in myblog directory. by executing below command in myblog directory.

    $ hugo server
    Started building site
    0 draft content
    0 future content
    1 pages created
    0 non-page files copied
    7 paginator pages created
    3 tags created
    2 categories created
    in 63 ms
    Watching for changes in /home/pradip/github/myblog/{data,content,layouts,static,themes}
    Serving pages from memory
    Web Server is available at http://localhost:1313/ (bind address 127.0.0.1)
    Press Ctrl+C to stop
    

    Now, open http://localhost:1313/ in your browser to find your blog up and running. If you make any changes to your posts while server is running, it detects the changes and reloads browser to show the changes - very handy to preview your changes real-time.

    You can now customize blog’s features and styling further as you wish. Read hugo theme docs for more details.

2. Host your blog on GitHub

Let’s host our little blog so that we can access it on interweb. GitHub lets us host a site directly from a special repository. Head over to GitHub and create a new repository named username.github.io, where username is your user name on GitHub. If the first part of the repository doesn’t exactly match your username, it won’t work, so make sure to get it right.

We will put our hugo generated blog (i.e. only contents of public directory from myblog directory) in username.github.io. Make sure to replace username with your GitHub user name in below commands.

$ cd $HOME
$ git clone https://github.com/username/username.github.io.git
$ cp -r myblog/public/* username.github.io/
$ cd username.github.io
$ git add --all
$ git commit -m'first version'
$ git push origin master

You will see contents of public directory in your GitHub repository now. Open https://username.github.io to see your blog live. Hurrah!

3. Auto deploy your blog with Drone.io

We have our blog live!. What next? We will keep adding contents to this blog. For every change in blog which we want to make live, we need to re-generate static site using hugo and push it to username.github.io. Doing it manually every time is no fun. That’s where we call Continuous Integration services to the rescue.

There are several CI tools today, I chose Drone.io as it needs minimal configuration to get the work done. Also it allows us unlimited builds for unlimited public repositories.

  • Add source code to a new GitHub repository Create a new GitHub repository with same name as our created blog i.e. myblog Source code needed for Hugo to build our blog is everything except public directory. So no need to upload public directory to myblog repository. Let’s put it in .gitignore file (git ignores files/directories matching patterns in this file).

    $ echo "./public" > .gitignore
    

    Also, we have cloned hugo-uno theme from external repository. Let’s link that repository as submodule instead of uploading whole theme in our repository.

    $ git submodule add https://github.com/SenjinDarashiva/hugo-uno themes/hugo-uno
    

    This will create .gitmodules file.

    $ cat .gitmodules
    [submodule "themes/hugo-uno"]
    path = themes/hugo-uno
    url = https://github.com/SenjinDarashiva/hugo-uno
    

    We’re ready to populate myblog repository.

     $ git add --all
     $ git commit -m'committing source'
     $ git remote add origin https://github.com/username/myblog.git
    
  • Create build script: Copy my build script deploy.sh in myblog directory and make it executable.

    $ curl https://raw.githubusercontent.com/pradippatil/myblog/master/deploy.sh > deploy.sh && chmod 755 deploy.sh
    

    Edit deploy.sh to replace username and email from below params with your username and email.

        git config user.name
        git config user.email
        git remote add upstream
    
  • Create a GitHub personal access token for Drone.io to push our static blog to username.github.io repository. Use this url and choose public_repo as scope. Copy and Paste generated token for use in next step.

  • Configure build on Drone.io

    • Register on Drone.io using GitHub account.
    • After successful registration. Select New Project -> GitHub -> It’ll list all repositories, including our new myblog -> Select myblog -> Select Go -> write ./deploy.sh in build script window -> write GH_TOKEN=<paste here token generated in previous stage> in Environment Variables section –> Click on Save
    • Done!
  • Submit all changes to myblog repository.

    $ git push -u origin master
    

    As soon as you push the changes in myblog repo, Drone.io will start to build using deploy.sh and after successful build, it will push public directory to username.github.io repository. That’s it! You can access your blog at https://username.github.io.

Yay! We’ve just created a version controlled blog with automated deployment. Let me know how does it work for you in comments.

P.S. You can check source for this blog here.