Self Serving Hugo Website

992 Words 6 August 2023

Hello everyone! In this piece, I’ll show you how to set up your very own Docker stack with NGINX and rsync, making it super easy to deploy your applications using GitHub Actions. It’s a fantastic way to streamline your development process and get your apps up and running quickly.

We’ll walk through the steps together, from configuring your Docker environment to setting up NGINX for reverse proxy and load balancing. Plus, we’ll integrate rsync for smooth file synchronization. By the end, you’ll have a slick deployment system, ready to handle your app deployments like a pro.

Whether you’re a seasoned developer or just getting started with Docker and GitHub Actions, this guide is designed to be straightforward and informative. So, welcome, folks, let’s jump right in and discover how to rock your deployments in no time! Let’s get started!

Prerequisits

There are a few preliminary steps, which need to be taken care of before proceeding.

Configure the docker containers

In our screnario we have a reverse proxy, which will route the traffic to the correct containers, while also providing SSL encryption. Reverse proxy can route traffic to containers which are attached to the same network. In our case we name it internal_network.

We will deploy two containers, one for rsync and one for nginx server. We will attach the nginx container to the internatl_network. We will also need to create a new volume, which we will attach to both containers. rsync will get the files from github actions pipeline and save them onto the hugo_data. The nginx container will serve the site from the same volume. We create volumes using portainer interface, but we could also use docker directly:

1
docker volume create hugo_data

We will further need to configure ssh keys. In the /root/.ssh/ we create new key, for just this pipeline.

1
ssh-keygen -t rsa -b 4096 -C "your.mail@mail.com" -f /root/.ssh/hugo

The mail needs to be changed. This will create two files hugo and hugo.pub. You need to add this public to authorized keys.

1
cat /root/.ssh/hugo.pub >> /root/.ssh/authorized_keys

Lastly, we need to configure nginx container. We select arbirary location /root/config/nginx/nginx.conf on the host server. With the following config:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
  user www-data;
  worker_processes auto;
  pid /run/nginx.pid;
  include /etc/nginx/modules-enabled/*.conf;

  events {
    worker_connections 768;
  }

  http {
    server{
      listen 8080;
      server_name _;
      # The nginx will serve files from this directory
      root /sites/hugo;
      location / {
          index index.html
          try_files $uri $uri.html $uri/ =404;
      }
      location ~ \.css {
        add_header  Content-Type    text/css;
      }
      location ~ \.js {
        add_header  Content-Type    application/x-javascript;
      }
    }
  }

We will need to build a custom rsync image before continuing

1
2
3
4
5
6
7
FROM alpine:latest
RUN apk --no-cache add rsync openssh bash
RUN ssh-keygen -A
RUN echo "PubkeyAuthentication yes" >> /etc/ssh/sshd_config
RUN echo "PasswordAuthentication no" >> /etc/ssh/sshd_config
EXPOSE 22
CMD ["/usr/sbin/sshd" "-D"]

In the next step we bring all of these configurations together:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
  version: '3.9'

  services:
    rsync:
      image: custom_rsync:latest
      volumes:
        - hugo_data:/sites/hugo
        - /root/.ssh:/root/.ssh:ro
      ports:
        - 2222:22

    nginx:
      image: nginx:latest
      volumes:
        - /root/config/nginx/nginx.conf:/etc/nginx/nginx.conf:ro
        - hugo_data:/sites/hugo
      networks:
        - internal_network

  volumes:
    hugo_data:
      external: true

      networks:
    nginx:
      internal_network: true

Configure the Github Actions

Github provides a nice way of configuring automatic deployment with Github actions. To configure this simply create a new directory in the repository if it doesn’t exist already (.github/workflows/deploy.yml).

Before we start configuring deployment actions, first we need to configure a few secrets with GitHub. Navigate to the repository and then to settings. Under security tab you will find secrets and variables. Then navigate to actions and then add a few secrets. Add the following secrets:

The following deploy script will execute steps when push to master branch has been pushed to the repository. The steps perform the following actions:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
  name: Deploy

  on:
    push:
      branches:
        - master

  jobs:
    deploy:
      runs-on: ubuntu-latest

      steps:
        - name: Checkout code
          uses: actions/checkout@v3
          with:
            submodules: true
            fetch-depth: 0

        - name: Setup Hugo
          uses: peaceiris/actions-hugo@v2
          with:
            hugo-version: '0.110.0'
            extended: true

        - name: Build Hugo ste
          run: hugo --minify

        - name: Install SSH Key
          uses: shimataro/ssh-key-action@v2
          with:
            key: ${{ secrets.SSH_PRIVATE_KEY }}
            known_hosts: 'empty'

        - name: Adding Known Hosts
          run: ssh-keyscan -p 2222 -H ${{ secrets.SSH_HOST }} >> ~/.ssh/known_hosts

        - name: Deploy with rsync
          run: rsync -avz --delete -e "ssh -p ${{ secrets.SSH_PORT }}" ./public/ ${{ secrets.SSH_USER }}@${{ secrets.SSH_HOST }}:/sites/blog_deploy/

Concluding

In conclusion, we have configured a pipeline, where after updating the repository, the server automaticallly updates using a pipeline through Github or Gitlab.