My Hugo Setup

2 minute read

WARNING: this post is deprecated as I have moved from Hugo to Jekyll


Static blog isn’t a new thing for me. I have known Jekyll, Octopress, Pelikan, Hugo, and so on. Now I’m trying out Hugo, this blog you’re reading is generated automatically from my GitHub repository for every push I make.

the idea

As a [DevOps engineer in my daily job, I’m accustomed to multi-environment setup (e.g. prod/dev environments) for deployment. Somehow I feel the urge to apply it to this blog as well *ahemm*. The branch mapping goes like this:

  • master → (prod)
  • develop → (dev)

The point is that develop is used as “draft” branch so I can try out new features/hacks that might not work on my local machine. I’d love to mindlessly push to develop when doing some trial-and-error hacks, sparing myself from making the local machine behave like the live server.

Furthermore and obviously, the two environments have common configs but differ a little. For instance, the dev should build draft posts as well (i.e. Hugo’s --buildDrafts` flag).


For simplicity, I choose Caddy to serve static files created by Hugo. You should give it a try too. Caddy’s configuration is very simple and has built-in support for Git and webhook which are the features I appreciate the most in this setup.

    root /var/www/html

    header / {
        X-Frame-Options DENY
        Referrer-Policy "same-origin"
        X-XSS-Protection "1;mode=block"

    log stdout
    errors stdout

    git {
        branch {$GIT_BRANCH}
        path /var/www/app
        hook /webhook {$WEBHOOK_SECRET}
        then git submodule update --init --recursive
        then hugo -v {$HUGO_OPTS} --destination=/var/www/html

Notice the variables? I make it like that so the environment can have different configs, hence the name “environment variables”. For instance, GIT_BRANCH has the value develop in dev, while master for prod. You got the idea.

The interesting part is in the git block. It sets source dir in /var/www/app and does Hugo build to /var/www/html whenever a webhook call is made to /webhook endpoint. Kudos to Aleksandr Tihomirov for the idea in his blog post!

So my blog repository on GitHub has two webhooks:


Every push to the repo will trigger both environments to re-generate blogs from their respective branches.


I run Caddy servers (yes, not just one) with the above configuration behind reverse proxy running on Docker. I won’t explain it in detail, but the general structure goes like this:

Final Setup

That’s it.

what’s next?

I’m still hacking around to add Isso commenting system to this blog. It’s a self-hosted alternative to Disqus or IntenseDebate, so I’ll write another blog post about getting it works.


Related links

  • (I take the idea from here)