Programmer by day, sysadmin by night. I like to write about tech and travel.

github email
Auto-deploy Hugo blog with gitlab webhooks and Caddy.
Oct 12, 2018
3 minutes read

Hugo is a static site generator that I find to be perfect to host a personal blog. All my blog content is version controlled and lives in a git repository. My usual blogging workflow goes like this

  1. Write a new post on my laptop.
  2. Commit and push it to the git repository.
  3. ssh to my the machine that serves my blog.
  4. git pull on that machine and run hugo to generate static pages. My web server is configured to serve the static pages that Hugo outputs.

Wouldn’t it be nice to automate steps 3 - 4 and let the blog auto-deploy new content when I push to the git repository? I managed to do just that with the wonderful Caddy server.

Caddy is a HTTP server with automatic HTTPS using Let’s Encrypt. For our purposes though, we are going to use Caddy with it’s http.git plugin. http.git plugin runs during the lifetime of the server, keeps polling a git repository for changes and pulls new changes. Once it pulls new changes, it can execute a command - perfect for running Hugo! Additionally, with the help of webhooks, caddy server can immediately pull after a push to the repository and our blog updates in an instant!

Configuring a webhook and Caddy

I use GitLab to host the git repository for my blog. To configure a webhook, I went to Settings -> Integrations in the GitLab project and I added a new webhook to notify Caddy at path __webhook__ on pushes to the repository like so (replace <secret> with your own and https://abhinandh.com with your own blog URL):

GitLab webhook configuration

Next we configure the Caddy server with the repository, the webhook we just configured and to run Hugo when it pulls new changes from the git repository. I run Caddy in a docker container behind a proxy that terminates SSL so I don’t use HTTPS in the Caddy configuration, please adapt the Caddyfile to your needs - Caddy has excellent documentation. Also make sure to replace <address of the git repo> and <secret> with those of your own actual values. {
    root /var/www/public

    git <address of the git repo> /var/www {
        hook /__webhook__ <secret>
        hook_type gitlab
        then hugo
        clone_args --recursive
        key /ssh/id_rsa


Finally, to put all these pieces together, I wrote a dockerfile for a container that will serve our blog. The dockerfile installs both Caddy with the http.git plugin and Hugo. It then copies the configuration file for the Caddy server and the ssh private key to authenticate with the GitLab git repository into the container.

FROM alpine
MAINTAINER Abhinand <blog@abhinandh.com>

RUN apk --update add git ca-certificates curl openssh \
    && rm -rf /var/cache/apk/*

RUN echo "Installing Caddy..." \
    && curl -jksSL "https://caddyserver.com/download/linux/amd64?plugins=http.git&license=personal" | gunzip -c - | tar -xf - -C /tmp \
    && mv /tmp/caddy /usr/local/bin/caddy \
    && rm -f /tmp/*.txt

RUN echo "Installing Hugo ..." \
    && curl -jksSL "https://github.com/gohugoio/hugo/releases/download/v${HUGO_VERSION}/hugo_${HUGO_VERSION}_Linux-64bit.tar.gz" | gunzip -c - | tar -xf - -C /tmp \
    && mv /tmp/hugo /usr/local/bin/hugo

RUN adduser -D -u 500 www && mkdir -p /var/www && chown -R www /var/www

COPY Caddyfile /etc/Caddyfile
COPY id_rsa /ssh/id_rsa
RUN chown www /ssh/id_rsa

WORKDIR /var/www
USER    www
CMD [ "caddy" , "--conf", "/etc/Caddyfile" ]

And that’s it! Hello instant and automatic blog deploys.

Back to posts