Hosting A Hugo Website Behind Nginx

I’ve been exploring Hugo lately. Interesting.

There are many Content Management Systems (CMS) in the world - this site you’re reading is hosted within Drupal. But I’ve always felt that a live CMS is sometimes a needlessly heavy-weight solution to the problem of authoring content and handling the digital assets to go with it. Even large corporations blunder into complex arcane content management, maybe suffering poor productivity and bad performance, with expensive licences to boot.

Dynamic or Static?

A traditional CMS has at its core a clever program that renders HTML pages on the fly by assembling content from a database. This is essential for ‘portal’ content tailored to individual users. But the dynamic approach using a database is overkill for almost all ‘brochure-ware’ websites.

Enter static site generators.

A static site generator produces a website on a production line basis - it churns out flat HTML files every time there’s a significant content change. The HTML is served by a standard webserver. There’s much less to go wrong, far fewer security worries and much much better performance (therefore lower cost in production). It’s a matter of horses for courses - sometimes, a CMS will be just right. But not always.

Just as there are many dynamic CMS systems, there is a growing number of static site generators too. I found a useful tracker for popular static site generators. Then I chose Hugo - reasonably simple to learn yet feature-rich. Easy to create templates and themes. Easy to add content … any amount of content you like. And very fast.

Write your content in text files. Write some templates. Write some CSS, digital assets, and fancy Javascript. Then hand it over to Hugo: my new site takes 1/4sec for Hugo to do its work - fast enough to do it over and over, every time anything changes.

Now store your content files in a version control system (Mercurial, Git, etc) and you have a safe and secure development environment for your a small to medium team, with very little complexity.

Static site generation may not be a new idea, but it’s a good one, and has only really taken off big-time over the last year or two.

Serving Hugo Content

Hugo comes with its own built-in webserver. It’s written in Go, a language that is proving itself supreme at heavy-I/O server applications. So it will no doubt perform well, and did indeed do so in my quick benchmark tests - it’s probably better than Apache.

That puts Hugo’s server in the same performance league as Nginx. Performance-wise, they may well be neck and neck. So other factors will decide between the two.

I currently host several Nginx sites. Administering the server for many co-hosted sites is straightforward. I’ve only got one port 80 per server and so Hugo won’t be used as the webserver. Not for now at least.

Now that I’ve got a Hugo-generated site amongst my other sites, I added a new Nginx server and set up the necessary DNS records.

Here’s a server configuration like I used:

    server {
        # List of domain patterns for this website
        server_name  mycodev;

        # Main listening port
        listen   80;

        access_log  /home/websites/myco/log/access.log;
        error_log   /home/websites/myco/log/error.log info;

        root  /home/websites/myco/htdocs/;

        location / {
            index index.html;
            try_files $uri $uri.html =404;

        # far-future aggressive caching for asset files
        # - this is optional - tune it to suit your content change rate
        # - assumes that once an asset exists, it is stable
        location ~* \.(gif|jpg|png|css|js|ico|au|mp3|ttf)$ {
            expires  30d;

            # you might prefer much shorter caching, e.g
            # expires  5m;

            # or the maximum possible
            # expires  max;

        error_page  404  /404.html;
        charset utf-8;

I run Hugo with the --uglyUrls=true option. It will create ‘plain old’ html files and Nginx will be happy with these. The try_files directive, above, makes Nginx serve html files with optional .html extension. So you get the best of both worlds: on the filesystem, you see a traditional collection of html files and their assets. Meanwhile, in the browser, you see ‘clean’ URLs (no .html suffix). Nice.

comments powered by Disqus