The Hugo manual provides a good introduction to automated deployments via Wercker but focuses on deploying to Github pages. After some trial and error, I’ve built a good setup for deploying to a Digital Ocean droplet.

If you’re looking for background information, read the Software section. For the instructions, skip ahead to Procedure.

Software

Hugo

Hugo is a static blog generator written in Go. Like Jekyll, Hugo processes a directory of Markdown-formatted posts and generates HTML output. I am using Hugo 0.13 at time of writing, but later versions should work similarly. After originally hosting this blog with Wordpress, then Ghost, I have found Hugo to be much faster (because of its static nature) and the easiest to self-host. Documentation is excellent and the project frequently adds new features. If you haven’t given Hugo a try, I highly recommend giving it a try. Between Hugo and Github Pages, it’s never been easier to create and host a good-looking site for free.

I have a Digital Ocean droplet left from my time hosting Wordpress and Ghost blogs, so I decided to host this blog on Digital Ocean instead.

Hosting the source code

This website’s source code is hosted on Bitbucket. GitHub is an equally good choice for hosting the Markdown files that Hugo will parse; it comes down to a matter of personal preference. When creating a repository, I recommend keeping it public to make integration with Wercker easier.

Digital Ocean

Digital Ocean is the backbone of this website. The server runs Nginx on Ubuntu 14.04 x64 to serve HTML pages generated by Hugo to visitors. This post assumes you have already set up a droplet with a working web server; if you have not, Digital Ocean provides excellent guides to get you up to speed. For security reasons, I recommend providing a public key to Digital Ocean and private-key authentication for login and never setting a root password.

Wercker

Wercker is a platform for building and deploying applications. In this case, we will be using Wercker to build and deploy the application.

Procedure

If you already have a Digital Ocean droplet set up, continue to the next paragraph. If not, hold off until after creating a new Wercker application; you will be able to create a new droplet with Wercker’s SSH key already populated in /root/.ssh/authorized_keys.

Next, make sure Hugo works. The Hugo quickstart includes instructions for installing Hugo and running a simple site from your local machine. After ensuring that Hugo builds the website correctly with hugo server --theme=herring-cove (assuming that you have cloned the herrive-cove theme and placed it within your Hugo directory), add a new file to the base directory called wercker.yml. This file will provide Wercker with all the information it needs to build and deploy your website to Digital ocean. Inside the file, paste the following lines:

box: wercker/default
build:
  steps:
    - arjen/hugo-build@1.1.0:
        version: 0.13
        theme: <YOUR_THEME>
        flags: --buildDrafts=false
deploy:
    steps:
        - add-to-known_hosts:
            hostname: $HOSTNAME
        - mktemp:
            envvar: PRIVATEKEY_PATH
        - create-file:
            name: write key
            filename: $PRIVATEKEY_PATH
            content: $WERCKER_PRIVATE
            overwrite: true
        - script:
            name: remove old files
            code: ssh -i $PRIVATEKEY_PATH -l root -o UserKnownHostsFile=/dev/null -o StrictHostKeyChecking=no $HOSTNAME rm -rf /var/www/blog/*
        - script:
            name: transfer blog
            code: |
                scp -r -i $PRIVATEKEY_PATH public/* root@$HOSTNAME:/var/www/blog
                ssh -i $PRIVATEKEY_PATH -l root -o UserKnownHostsFile=/dev/null -o StrictHostKeyChecking=no $HOSTNAME chown -R www-data:www-data /var/www/
        - script:
            name: restart nginx
            code: ssh -i $PRIVATEKEY_PATH -l root -o UserKnownHostsFile=/dev/null -o StrictHostKeyChecking=no $HOSTNAME service nginx reload

Replace <YOUR_THEME> with the name of whichever theme you are using. If you are using Apache instead of Nginx, you will also need to change the final line to reload Apache. This file includes both configuration for Hugo (theme, whether to build drafts, and version) and Wercker instructions. Push the directory to the code-hosting service of your choice.

Now create a new application with Wercker. The steps are:

  1. Create -> Application
  2. Choose Git provider: whichever one you are hosting your files with
  3. Select your blog from the repository list
  4. Select owner: yourself
  5. Configure access: Check out without SSH key (this is why the blog’s code should be set to public).
  6. Setup your wercker.yml: Choose “I already have a wercker.yml”
  7. Finish.

Open the settings for your new application. By this point, Wercker is able to detect changes you make to your blog when you push the new posts to GitHub/ Bitbucket but is able to deploy the built website to Digital Ocean. Time to change that.

In the application settings, generate a new SSH key (SSH keys -> Generate new key pair). Name it something memorable to use later. Wercker will hold onto the private key and give you a public key for copying. Copy the public key to your clipboard.

If you already have a Digital Ocean droplet you will use, SSH into the droplet as root (ssh root@your-droplet-ip and edit /root/.ssh/authorized_keys. Paste the public key that Wercker generated for you, save the file, and exit.

If you have not yet created your droplet, open your Digital Ocean settings and add a new SSH key (located under Settings->Security). Now create a new droplet and add the SSH key to it during creation, in addition to your own public key, so that both Wercker and you can log in. Install Nginx on the server and make sure that it works, then continue.

Still in application settings, open the Deploy targets tab. Choose Add deploy target -> Custom deploy and give it a name. Select auto deploy successful builds to branch(es) and enter master for the branch name. Then add 2 variables to the deploy pipeline.

  1. Name the first variable WERCKER and choose SSH Key pair. Select the key pair you earlier generated and added to your Digital Ocean droplet. You will notice two variables generated, WERCKER_PUBLIC and WERCKER_PRIVATE. These correspond to the keys in /root/.ssh/authorized_files and wercker.yml, respectively.
  2. Name the second variable HOSTNAME and choose Text. In the text box, put the IP address or hostname of your Digital Ocean droplet.

Save the new settings. Now everything should work!

Testing

Wercker should have built your website after you set up the application. Open the application and navigate to the Builds tab. Find the latest build and open it. At the top there is a Deploy to button. Click it and deploy to the Digital Ocean droplet you just added in Deploy targets. Wercker will take care of transferring your website’s files to Digital Ocean via SSH and reloading Nginx to make sure that the changes take effect.

Congratulations, you’re hosting your own website!

Final notes

  • Wercker has been experimenting with a infrastructure stack built on Docker. This post was written with the old infrastructure stack in mind. If given a choice, choose to use the old stack (v1). The wercker/default box is not available when using the Docker-based infrastructure.
  • If the website looks like it’s missing a theme, make sure that the theme you have used on your local machine is part of your git repository and has been synced to Bitbucket/ GitHub. This has been the source of almost all my recent build/ deployment errors.
  • If a post isn’t appearing, make sure that it isn’t set to be a draft.
  • Thanks to the Hugo automated deployment guide for the basis of this post.
  • And a big thanks to Hugo, Wercker, and Bitbucket, for providing the software that turns this from a lengthy process into one step of git push magic!