I started this blog yesterday. I had always felt a need for a public space where I could share what I learn, but for some reasons, I had procrastinated it. I could finally overcome the gap, so I will describe the process in this post.

One of the reasons I could not get started with blogging is tooling. As for hosting solutions, WordPress seems too complicated for my need, and Medium does not provide a way to export a whole site. Generally speaking, I don’t like a hosted CMS, because it does not allow me to own my contents. And I even have issues in linguistic skills. If possible, I would like to switch to a custom workflow that aids linguistic usage.

I don’t like other static site generators. I don’t like those that are written in a dynamic language, like Jekyll, because they are slow and likely to be broken by a system update. I also don’t like how Jekyll organizes a site. Hakyll is written in Haskell, and I know some Haskell, but Haskell is hard to distribute. It actually needs GHC in order to compile your site configuration. It is better not to depend on GHC to write a blog.

Hugo is written in Go, distributed as a single executable, and runs fast. It is popular and has plenty of features for producing versatile sites. It is not as simple as I wish, and some people claim that it is an overkill for a personal blog, but its sophisticated design seems to worth learning. By “design”, I don’t mean its application design here. I haven’t learned how to write Go code. Rather, it is about conventions on how to organize static contents, including meta-data and templates. If I had started from scratch, I would probably have to reinvent a lot of wheels. I am not so confident. I ought to avoid it.

Actually, I also considered some static site generators written in JavaScript. Of those, I was especially interested in Harp, which presented a unique way to organize static contents. However, I didn’t like its centralized meta-data instead of front matters, and its development has been inactive. There must be a reason people would not use it. Perhaps you should use a database application instead of Harp. It is what web applications do nowadays. Anyway, I went for Hugo over node.js solutions because of its performance.

And I found a good place for hosting static sites: Netlify. It allows me to host a public static site on a custom domain for free. Surge is another choice, but I encountered some information which claims that Netlify is better than Surge. One of the advantages of Netlify over Surge is continuous deployment. You can link a Netlify site to a repository on GitHub/BitBucket/GitLab, and every time push commits to the repository, Netlify runs a site generator specified by the user and updates the site content with its output. And Hugo is included in the supported static generators, so if you use Hugo, it is recommended to host your site on Netlify.

Overview

This setup uses the following tools and services:

  • Hugo, a static site engine written in Go
  • Netlify, a static web site hosting service (CDN)
  • The domain is registered by namecheap, and its name server is used
  • GitHub is used to host a private repository of source code, but this can be anywhere

The site is hosted at jingsi.space without sub-domains. No www. If a user visits www.jingsi.space, he/she is redirected to jingsi.space.

Building a site with Hugo

For Arch Linux users, Hugo is available as hugo-bin package from Arch Linux User Repository. For other users, look at the download page of Hugo.

Initializing a site

Use hugo new site to scaffold a new site:

hugo new site jingsi-space-blog
cd !$
git init

By default, this command creates a basic config.toml and a bunch of directories.

Theming

A Hugo site needs a theme. You have to install one on your own. There are a lot of community works available in the theme gallery, and I chose Minos. I just want a readable theme without tons of user interface widgets, which would get in the way of readers including myself. Minos seemed to satisfy the requirement. Although its design has some minor issues such as the link style, it looks beautiful and is highly readable. It is also responsive, that is, it works on mobile browsers, as shown in the following screenshot:

My blog with Minos theme rendered on an Android browser

To install this theme to your Hugo project, run the following command:

hugo_theme_repo=https://github.com/carsonip/hugo-theme-minos
hugo_theme_name=hugo-theme-minos
git fetch --depth=1 $hugo_theme_repo
git subtree add -P themes/$hugo_theme_name --squash $hugo_theme_repo HEAD       

Then set the theme in config.toml of your project:

theme = "hugo-theme-minos"

Other site settings

I also set some other parameters in config.toml, and now it has the following content:

languageCode = "en-gb"
title = "jingsi.space"
baseurl = "https://jingsi.space/"
defaultContentLanguage = "en"
metaDataFormat = "yaml"
theme = "hugo-theme-minos"

[permalinks]
  post = "/post/:year/:month/:day/:title"

I prefer YAML over TOML as the front matter format, as it is much more widely adopted.

Developing in the watch mode

While you are writing a draft, you can preview your site by running the following command in the background:

hugo server --watch --buildDrafts

This watch mode supports hot reloading, so you don’t have to refresh the web page manually on your web browser.

It is a little boring to type this command every time you write a post, so let’s add it to package.json of JavaScript npm. This is not a node.js project at all, but I install npm onto my machines anyway, so relying on npm run (or yarn run) is quite acceptable for me.

First, initialize package.json:

npm init -y

Then add watch command to scripts section of the file:

  "scripts": {
    "watch": "hugo server --watch --buildDrafts"
  },

Now you can run a server by simply running the following command:

npm run watch

Writing a post

To create a new post in your project:

hugo new post/FILENAME.md --editor typora

Typora is a Markdown editor I am currently using. It runs on Windows, OS X, and Linux, and it is free during beta. Of course, you can use any text editor, or omit the option if you just want to create a file. The created file is actually content/post/FILENAME.md.

You can find drafts in your project using the following command:

hugo list drafts

To finish a post and remove the draft status, use hugo undraft command:

hugo undraft content/post/FILENAME.md

Server configuration

DNS settings on Namecheap

I registered my jingsi.space domain via namecheap. It was cheap.

It is possible to use the whole domain to host only a static blog. In that case, all you have to do is to choose “custom name servers” option on namecheap, and add the name servers of Netlify (or any other service hosting your site) to the server list. However, I plan to run other services in its sub-domains, and only jingsi.space without a sub-domain should point to my static blog. Therefore I added the following A record to my DNS settings:

  • Type: A record
  • Host: @
  • IP address: 104.198.14.52
  • TTL: automatic

The IP address in this record points to a load balancer of Netlify. On namecheap, you can do this setting in “Advanced DNS” section of your domain. You can also use name servers by any provider you want to use instead, like DigitalOcean.

Then you can add another A record that points to your load balancer or reverse proxy such as Traefik, running on a VPS to host more services. I may do it in the near future, but not for now.

In order to redirect access to www.jingsi.space to jingsi.space, I also added a CNAME record:

  • Type: CNAME record
  • Host: www
  • Target: jingsi.space.
  • TTL: 60 min

Creating a site on Netlify

To get started with a new site on Netlify, sign up for a new account and add a new project from the dashboard. Then you can configure detailed settings of your site on a web browser.

Custom domain

Visit Settings, and set the domain (to jingsi.space in my case).

Deploys

In Deploys section, you can review your history of site uploading. Actually, all of your versions are available from this page, and you can even rollback your site to a past version. This feature would be useful when you run some kind of post processing and it fails, but I don’t need it for now.

HTTPS

Let’s Encrypt provides SSL certificates for free. That means you can make your site accessible via HTTPS with no additional cost. And Netlify allows you to configure it easily in HTTPS section.

I don’t have any serious reasons to activate SSL on my blog, but as it provides several benefits, I enabled this feature and forced TLS connections.

For detailed discussions on using Let’s Encrypt, read Let’s Encrypt Everything.

Deploying the site to Netlify

Continuous deployment

Netlify supports continuous deployment of static sites. When this feature is enabled, it automatically runs a specific build program to rebuild your project, and uses its output as the new version of your hosted site. This is an awesome feature which simplifies your workflow and spares the need for a site uploader. It supports GitHub, BitBucket, and GitLab as a repository host, and Hugo is included in one of the supported build programs.

After pushing the first version of your Hugo site to a remote repository on GitHub/GitLab/BitBucket, visit your site settings on Netlify and find Link to Git section. Authorize Netlify on the repository host, and choose the repository containing your site. Set the build command to hugo and the public folder to public. Now Netlify automatically rebuilds your site every time you push changes to the remote repository.

Alternative: Manual deployment with netlify client

Alternatively, you can use a command line application named netlify to upload your site contents from a computer. This is a dedicated client program developed by Netlify and can be installed via npm:

npm install -g netlify-cli

Initial deployment

Build your site for the first time:

hugo

Run the following command to publish your site to Netlify:

netlify deploy -p public

As Hugo produces output in public directory, you have to pass the directory to the command via -p option. It asks you a project of your destination, so choose the one you want to publish the contents to.

Adding a command to update the site

After you run netlify deploy for the first time in a project, per-project settings such as a public directory and a site identifier are saved in .netlify in your project directory. You don’t have to specify those parameters in the succeeding deployments. On the other hand, your access token is saved in global ~/.netlify/config, so it is safe to put the per-project .netlify file under version control:

git add .netlify

Then add the following scripts to package.json:

  "scripts": {
    "publish": "npm run build && netlify deploy",
    "build": "hugo",
    "watch": "hugo server --watch --buildDrafts"
  },

Now you can rebuild the site and deploy it to Netlify with the following single command:

npm run publish

Reproducible authoring environment

Continuous deployment

If you choose the continuous deployment track, you only need the following programs on your computer to write a post and publish it to Netlify:

  • hugo executable
  • A text editor supporting Markdown
  • git (and ssh) for repository operations
  • npm (optional; just to invoke hugo, and you probably don’t need it)

In a bad situation, you can omit hugo (and npm). You can create a draft manually, edit it, and undraft it by editing its front matter. You cannot preview the site, but this is not so bad if your Markdown editor supports built-in preview. You only need a Markdown editor and Git.

You even don’t need a computer. You can write a post directly on the repository hosting service via a web browser. If you host your repository on GitHub, you can consider prose.io as an online Markdown editor with support for GitHub.

Manual deployment

Even if you don’t use continuous deployment, it is strongly recommended that you should put the whole project under version control and push it to a repository hosting service. I created a private GitHub repository which is limited to a paid account, but it can be a public repository if you don’t care, or you can use BitBucket instead, which provides private repositories for free. It will serve as a backup of your project and also allow you to work on multiple machines.

After cloning the repository to a computer, you only need the following programs to write a new post and publish it:

  • git (and ssh) for repository operations
  • A text editor supporting Markdown
  • hugo executable
  • netlify client, which can be installed by npm install -g netlify-cli
  • npm (optional)

You have to install netlify client in order to publish the content, and you cannot omit hugo program. Compared to the continuous deployment scenario, this way requires more dependencies, but they are still not too many and can probably be installed safely on most environments.

Conclusion

Blogging with Hugo and Netlify is a breeze. With Hugo, you can easily build a static site, and with Netlify, you can easily deploy it to the cloud. The continuous deployment from a remote repository supported by Netlify even removes the need for the build program on computer, and thus makes your authoring environment even more portable and reproducible: You only need a sophisticated Markdown editor and Git. It is also possible to add/update posts via a web browser, using an online editor like prose.io. These facts made me gain a sense of safety about writing things online. It was easier and more resilient than I expected.