How to deploy a Zola website to server using GitHub Actions

2021-05-28

6 mins

So, you've made your website using Zola and want it to be automatically deployed to your server when you push to master on GitHub? It's actually rather easy to set up. I will be using Docker and Nginx to serve the website as well as Traefik as a reverse proxy in my examples as this is based on the setup providing automatic deployment for this very website but this should be easy to modify for your own setup.

Step 1: Create the service on the server

Create a folder at /srv/my-website.com

sudo mkdir /srv/my-website.com

Create a docker-compose.yml file in the same folder:

version: "3.5"
services:
  my-website-nginx:
    image: Nginx:1.12-alpine
    restart: always
    networks:
      - traefik-net
    labels:
      - 'traefik.enable=true'
      - 'traefik.http.routers.my-website.rule=Host(`my-website.com`)'
      - 'traefik.http.routers.my-website.entrypoints=websecure'
      - 'traefik.http.routers.my-website.tls=true'
      - 'traefik.http.routers.my-website.tls.certresolver=le'
    volumes:
      - ./Nginx:/etc/Nginx/conf.d/
      - /srv/my-website.se/public/:/var/www
networks:
  traefik-net:
    external: true

Finally create a file at /srv/my-website.com/nginx/my-website.conf

server {
  listen         80 default_server;
  server_name    my-website.com;

  location / {
    root /var/www/;
    default_type application/json;
    add_header Access-Control-Allow-Origin  *;
  }
}

The docker-compose file when launched will run Nginx with the configuration file described above. It will simply serve everything placed in the /srv/my-website.com/public folder statically. The goal is to automatically build your Zola project and copy the resulting /public folder there.

Step 2: Create a user

For safety reasons we will now create a new user that only has permissions to modify /srv/my-website.com/. This user will be used in the GitHub Action to copy the files over later.

Create a user:

sudo useradd github

Then give the user a password. This should only be used when testing the deployment process, any access via SSH should be trough keys only.

sudo passwd github

Then create a home folder for the new user, and give it ownership of /srv/my-website.com and it's home.

sudo mkdir /home/github
sudo chown -R github /srv/my-website.com
sudo chown -R github /home/github

Step 3: Set up GitHub secrets.

For the action and access to work we first need to generate a keypair using ssh-geygen. Make sure to not enter a passphrase. This will generate two keys: a public and a private key. Copy the public key to /home/github/.ssh/authorized_keys/ (the public key ends with .pub, the other is the private key).

Go to the GitHub project containing the Zola project, go to 'Settings', go to 'Actions' and then 'Secrets' and add the following:

  • HOST: The URL to the server you will be deploying your website on.
  • PORT: The port that accepts SSH on your server.
  • USERNAME: The name of the user deploying to your server. If you followed my examples it would be github
  • KEY: The private key of the keypair you just generated.

After setting up the GitHub secrets you should delete the private key from where you used ssh-keygen.

Finally repeat repeat this from part 2:

sudo chown -R github /home/github

This makes sure the github user has access to the authorized public key.

Step 4: Set up a GitHub runner.

For the automatic deployment to work you need a GitHub runner. If you already have one skip this step but just make sure it has Zola installed or modify the action to install Zola.

First, create a GitHub Personal Access Token. On the GitHub website go to 'Settings', 'Developer settings' and then 'Personal access tokens'. Create a new one and give it access to repos and make sure to save it as it will only be displayed once.

Create a file Dockerfile in srv/my-website.com:

FROM myoung34/Github-runner

# Install build dependencies
RUN apt-get update && apt-get install -y cargo make libssl-dev g++

# Clone and build Zola
RUN git clone https://github.com/getzola/zola /zola
WORKDIR /zola
RUN cargo build --release --target x86_64-unknown-linux-gnu
RUN mv target/x86_64-unknown-linux-gnu/release/zola /usr/bin

# Go back to initial workdir to not break the base image
WORKDIR /
WORKDIR /actions-runner

This extends the myoung34/Github-runner by installing the dependencies needed to build Zola and then builds Zola. This might take some time but is only necessary when rebuilding the image. Then add the following lines to the previously defined docker-compose under services:

  github-runner:
    build: ./
    environment:
      REPO_URL: https://github.com/YourGithubUserName/YourZolaProjectRepo
      RUNNER_NAME: my-website-runner
      RUNNER_WORKDIR: /tmp/runner/work
      ACCESS_TOKEN: $ACCESS_TOKEN
      LABELS: linux,x64
    volumes:
      - '/var/run/docker.sock:/var/run/docker.sock'
      - '/tmp/runner:/tmp/runner'

Replace $ACCESS_TOKEN with your own Personal Access Token that you just generated.

Running docker-compose up (add -d if you want it to run in the background) in /srv/my-website.com should now start an Nginx server statically serving files in /public as well as a GitHub runner. You can test that it works by putting anything into a index.html file in /public and visiting my-website.com/index.html. To confirm that the GitHub runner is working visit your repo, go to to 'Settings', 'Actions' and then 'Runners' where it should now show up.

Step 5: Create the GitHub Action

In the repo containing your Zola project create the directories .github/workflows/:

mkdir -p .github/workflows/

Then add a file called zola.yml:

name: Zola

on:
  push:
    branches: [master]

jobs:
  build:
    runs-on: self-hosted
    steps:
      - name: Checkout
        uses: actions/checkout@v2
      - name: Zola Build
        run: zola build
      - name: Save Artifact
        uses: actions/upload-artifact@v2
        with:
          name: public
          path: public/
  deploy:
    needs: build
    runs-on: self-hosted
    steps:
      - name: Downloads public Artifact
        uses: actions/download-artifact@v2
        with:
          name: public
      - name: Deploys to server
        uses: burnett01/rsync-deployments@4.1
        with:
          switches: -ahvze --delete
          path: public/
          remote_path: /srv/my-website.se/public/
          remote_host: ${{ secrets.HOST }}
          remote_user: ${{ secrets.USERNAME }}
          remote_key: ${{ secrets.KEY }}
          remote_port: ${{ secrets.PORT }}

This described an GitHub Action with two jobs. The first job is called build and first builds the project and then saves the resulting /public folder as an artifact. The second job called deploy waits for build to complete and then downloads the /public folder artifact and uses rsync to only copy the changes over to your server (including removing files). If all the steps have been followed correctly you should now be able to push to the master branch of your repo and automatically have the website deployed!

GitHub secrets can be used by everyone with collaborator access to your repository so only use this on repositories where it would be safe. They can not be used by pull requests from forks.

Comments

Please be respectful. No spam or advertising.