Continuous deployment of a Hugo website to shared hosting

Avatar
Sep 1, 2020
Image

After I converted my personal website to the static site generator Hugo, I ran into a problem. Every time I wanted to make an adjustment to my site I had to go through the following steps:

  1. Make the change
  2. Commit and push to Github
  3. Build the site with Hugo
  4. Upload the output of the public folder over FTP to my webhost.

To speed up this process I started using Github Actions. As soon as I push the changes to the master branch the site needs to be built and uploaded.

Creating a Github Action

The first step is to create a Github Action. To achieve this, you need to create a file in the .github/workflows folder. The name of this file is not important, but the metadata filename must be either action.yml or action.yaml. I use build-and-deploy.yml.

Building and deploying

1. Checkout code

First we checkout our repository so that our workflow can access it.

name: Build and deploy Hugo site
on: [push]
jobs:
  deploy:
    runs-on: ubuntu-18.04
    steps:
      - uses: actions/checkout@v2.1.0

2. Build with Hugo

The next step is to build our Hugo site. We achieve this using actions-hugo. I use the --minify flag, but it can be replaced by -D for example if you want to include drafts or just hugo is also sufficient.

- name: Setup Hugo
  uses: peaceiris/actions-hugo@v2
  with:
    hugo-version: '0.74.3'

- name: Build
  run: hugo --minify

3. Deploy with FTP

Finally, the content of the public must be uploaded via FTP to the webhost. It is nessesary to add the username (FTP_USERNAME) and password (FTP_PASSWORD) as secrets on your Github repository.

- name: Deploy
  uses: kevinpainchaud/simple-ftp-deploy-action@v1.1.0
  with:
    ftp_host: ftp.niekvanleeuwen.nl
    ftp_username: ${{ secrets.FTP_USERNAME }}
    ftp_password: ${{ secrets.FTP_PASSWORD }}
    local_source_dir: "public"
    dist_target_dir: "/"
    delete: "false"

If you want to exclude a file or folder, this is also possible by adding the following entry

exclude: "'^logs/' '^README.md'"

Result

If we merge the above code snippets we reach the following result

name: Build and deploy Hugo site
on: [push]
jobs:
  deploy:
    runs-on: ubuntu-18.04
    steps:
      - uses: actions/checkout@v2.1.0

      - name: Setup Hugo
        uses: peaceiris/actions-hugo@v2
        with:
          hugo-version: '0.74.3'

      - name: Build
        run: hugo --minify

      - name: Deploy
        uses: kevinpainchaud/simple-ftp-deploy-action@v1.1.0
        with:
          ftp_host: ftp.niekvanleeuwen.nl
          ftp_username: ${{ secrets.FTP_USERNAME }}
          ftp_password: ${{ secrets.FTP_PASSWORD }}
          local_source_dir: "public"
          dist_target_dir: "/"
          delete: "false"

Thanks for reading! If you have found a mistake, want to ask a question or have a comment, please send me an email.

arrow-up icon