Henry V Child 75af981c64
Some checks failed
Generate and upload hugo website / generate_and_uplaod_site (push) Has been cancelled
Fixed wrong filename and set post draft to false
2025-02-19 20:41:14 +01:00

6.5 KiB

date draft title
2025-02-17T21:16:00+01:00 false Automating my website using the Gitea act runner

Currently, when I make a change or add content to my web page after committing my changes to Gitea, I need to manually build the web page using the hugo command and then copy the files to my web host. This process can be automated using the Gitea act runner!

With the runner I will be able to create containers to do automated tasks such as generating the hugo website and copying the final html to the webserver.

The Docker Container

I edited the docker-compose template in my Ansible role for Gitea to include the runner and the configuration for Gitea, notably enabling actions and including a token for the runner.

# This file is managed by Ansible, it would be best not to edit it manually!
---
services:
  server:
    image: docker.io/gitea/gitea:1.23.1-rootless
    container_name: gitea_server
    volumes:
    - data:/var/lib/gitea
    - config:/etc/gitea
    - /etc/timezone:/etc/timezone:ro
    - /etc/localtime:/etc/localtime:ro
    environment:
    - GITEA_RUNNER_REGISTRATION_TOKEN={{ gitea_runner_token }}
    - GITEA__actions__ENABLED="true"
    networks:
      - default
    restart: unless-stopped

  runner:
    image: gitea/act_runner
    container_name: gitea_runner
    restart: always
    depends_on:
    - server
    volumes:
    - runner_data:/data
    - ./runner_config.yaml:/config.yaml
    - /var/run/docker.sock:/var/run/docker.sock
    environment:
    - GITEA_INSTANCE_URL=https://gt.{{ domain_name }}
    - GITEA_RUNNER_REGISTRATION_TOKEN={{ gitea_runner_token }}
    - CONFIG_FILE=/config.yaml
    networks:
    -  ipv6

networks:
  default:
  ipv6:
    enable_ipv6: true

volumes:
  runner_data:
  data:
  config:

I'm using an IPv6 network in my home lab and try to have everything using it by default. IPv6 is supported in docker networks but is not activated by default. So to enable the runner to find the Gitea server, I created a docker network with IPv6 support and joined the runner to it. The following config was attached to the runner so that containers spawned from it also have IPv6 connectivity to for example clone repositories and copy files to the web server.

# This file is managed by Ansible, it would be best not to edit it manually!
---
container:
  network: "gitea_ipv6"

Using this docker compose file and config the Gitea server and runner are started and are able to connect!

!runner_status.png

The test job supplied by Gitea is run and is successful!

!job_success.png

Configuring the workflow

The workflow can be configured by creating a file under .gitea/workflows in any git repo. I created the following workflow in my websites repo to build and upload the website whenever changes are pushed to the repository.

---
name: Generate and upload hugo website
on:
  push:

jobs:
  generate_and_uplaod_site:
    runs-on: ubuntu-latest
    steps:
    - name: Update Packages
      run: sudo apt update

    - name: Install Go
      run: sudo apt install golang-go -y

    - name: Building Hugo
      run: go install github.com/gohugoio/hugo@latest

    - name: Check out repository code
      uses: actions/checkout@v4

    - name: Generate the website
      run: ~/go/bin/hugo

    - name: Sending my key to file
      run: echo "${{ secrets.RUNNER_SSH_KEY }}" > ~/key

    - name: Protecting keyfile
      run: chmod 600 ~/key

    - name: Adding siab to known hosts
      run: echo "siab.henv.eu ${{ secrets.SIAB_FINGERPRINT }}" > ~/.ssh/known_hosts

    - name: Copy files over to webserver
      run: scp -v -i ~/key -r ${{ gitea.workspace }}/public/* gitea_runner@siab.henv.eu:/srv/nginx/webpage

Firstly go is installed and then the Hugo application is compiled with go. Next the ssh keys, The private key for the container and the public key for the server, are copied into place to allow the generated website to be installed on the targeted server. These keys are configured in Gitea in the action secrets

!runner_secrets.png

However before this can work some work needs to be done on the server hosting the website. The runner needs a user that has the correct permissions to edit the web server files and that user needs to have the correct shh keys. Because I'm into automating as much as I can in my home lab I naturally edited my Ansible role for Gitea to make these changed for me. Below is my role for Gitea:

---
- name: Creating directory for container'
  become: yes
  file:
    path: /srv/gitea
    state: directory

- name: Copying over the docker-compose file
  become: yes
  template:
    src: docker-compose.yaml
    dest: /srv/gitea/docker-compose.yaml

- name: Copy over runner config
  become: yes
  copy:
    src: files/runner_config.yaml
    dest: /srv/gitea/runner_config.yaml

- name: Create the group for webadmins
  become: yes
  ansible.builtin.group:
    name: webadmin
    state: present

- name: Create runner user
  become: yes
  ansible.builtin.user:
    name: gitea_runner
    group: webadmin

- name: Copy runner public key
  become: yes
  ansible.builtin.copy:
    content: '{{ runner_pub_key }}'
    dest: /home/gitea_runner/.ssh/authorized_keys

- name: Allow Gitea access to file
  become: yes
  file:
    path: /srv/nginx/webpage
    state: directory
    owner: root
    group: webadmin
    mode: '775'

- name: Create and start the container
  community.docker.docker_compose_v2:
    project_src: /srv/gitea

Unfortunately I can't thing if an eloquent way of automating the creation of the ssh keys and setting them as Gitea secrets. So currently the creation of the ssh keys needs a little bit of manual effort. Firstly the ssh keys are generated using the following command:

ssh-keygen -f runner_key -t rsa -b 4096

The private key in the file runner_key is copied to the Gitea secrets, the public key is added to the variables section of the Ansible playbook. And finally the public ssh key of the server /etc/ssh/ssh_host_rsa_key.pub is added to the secrets as the fingerprint. In this case I logged into the server running my web server and copied the keys from there.

!the_workflow_works.png

After creating some content on my website and pushing the changes I'm able to see my new test post!

!my_post.png

There are definitely things to improve here. The runner container could use a purpose made image to run the container with Hugo already built. This would speed up the time it takes for the action to be run. However, this is my first real use of any CI/CD pipelines and I'm happy with the end result!