Creating my blog with Docker, Hugo, and Caddy


Tags: docker hugo caddy

A lonely web server

I pay for a small DigitalOcean droplet running Debian. I originally created it just to have a remote server with which to play around with various tools. One of which was to host a static site via nginx running in a Docker container. Nothing’s really changed with it since that initial setup, save running the container with systemd-nspawn1.

Let’s get blogging

Fast forward a few years, and I’ve been itching to try out some newer technologies. I was inspired by a Hacker News post2 to start a blog, even if it’s just to use as a personal journal or record of new things I’ve learned.

I wanted a platform that was easy to install, maintain, and update. Hugo fits the bill:

  1. It’s written in Go, so it’s a statically-compiled binary that’s easy to install and update.
  2. It’s fast. It compiles static web sites from templates and Markdown files in a few seconds.
  3. It’s got a lot of themes that are easy to tweak. I’m using Minimalist.
  4. Updating it is as simple as adding commits to a git repository.
  5. Testing new themes, configurations, and drafting new entries can be done anywhere. I can run this against my locally-hosted git repository to spawn a local daemon that will listen for new changes while I’m drafting a new post: hugo server --buildDrafts

How to host my blog?

I’m familiar with using nginx, and it’s a well-established web server. However, there are a lot of configuration tweaks that need to be done to get it to securely host a static web site. Another Hacker News post3 led me to Caddy, a secure-by-default web server written in Go and designed to host static web sites. Like Hugo, it’s a statically-compiled binary, so it’s easy to install. It also has nice addons like git that enable extra functionality.

This addon allows Caddy to clone my Hugo repository and run hugo to compile the blog:

 git {
    hook /somehook "secret"
    path ../git
    then hugo --destination=/srv/blog

Note that hook directive, which GitHub will trigger whenever I push new updates to the blog’s repository (the git addon also configures Caddy to check once an hour for new updates, by default).

Operationalization (a real word)

To get all of this daemonized, I’m using a Dockerfile with some static web files4 that runs a Docker container with Caddy and Hugo installed. Caddy clones my Hugo repository and waits for updates. Easy-peasy.

My blog’s git repo is hosted on GitHub here:

Future enhancements

One thing I’d like to do is start using Let’s Encrypt. They’ve made it very simple to automatically generate TLS certificates and keep them updated. Heck, as of 0.8, Caddy has support built in for automatically creating Let’s Encrypt certs5.