diff --git a/.gitea/scripts/add-annotations.sh b/.gitea/scripts/add-annotations.sh
new file mode 100755
index 0000000..eccec9d
--- /dev/null
+++ b/.gitea/scripts/add-annotations.sh
@@ -0,0 +1,114 @@
+#!/bin/bash
+
+set -e
+
+CHART_FILE="Chart.yaml"
+if [ ! -f "${CHART_FILE}" ]; then
+  echo "ERROR: ${CHART_FILE} not found!" 1>&2
+  exit 1
+fi
+
+DEFAULT_NEW_TAG="$(git tag --sort=-version:refname | head -n 1)"
+DEFAULT_OLD_TAG="$(git tag --sort=-version:refname | head -n 2 | tail -n 1)"
+
+if [ -z "${1}" ]; then
+  read -p "Enter start tag [${DEFAULT_OLD_TAG}]: " OLD_TAG
+  if [ -z "${OLD_TAG}" ]; then
+    OLD_TAG="${DEFAULT_OLD_TAG}"
+  fi
+
+  while [ -z "$(git tag --list "${OLD_TAG}")" ]; do
+    echo "ERROR: Tag '${OLD_TAG}' not found!" 1>&2
+    read -p "Enter start tag [${DEFAULT_OLD_TAG}]: " OLD_TAG
+    if [ -z "${OLD_TAG}" ]; then
+      OLD_TAG="${DEFAULT_OLD_TAG}"
+    fi
+  done
+else
+  OLD_TAG=${1}
+  if [ -z "$(git tag --list "${OLD_TAG}")" ]; then
+    echo "ERROR: Tag '${OLD_TAG}' not found!" 1>&2
+    exit 1
+  fi
+fi
+
+if [ -z "${2}" ]; then
+  read -p "Enter end tag [${DEFAULT_NEW_TAG}]: " NEW_TAG
+  if [ -z "${NEW_TAG}" ]; then
+    NEW_TAG="${DEFAULT_NEW_TAG}"
+  fi
+
+  while [ -z "$(git tag --list "${NEW_TAG}")" ]; do
+    echo "ERROR: Tag '${NEW_TAG}' not found!" 1>&2
+    read -p "Enter end tag [${DEFAULT_NEW_TAG}]: " NEW_TAG
+    if [ -z "${NEW_TAG}" ]; then
+      NEW_TAG="${DEFAULT_NEW_TAG}"
+    fi
+  done
+else
+  NEW_TAG=${2}
+
+  if [ -z "$(git tag --list "${NEW_TAG}")" ]; then
+    echo "ERROR: Tag '${NEW_TAG}' not found!" 1>&2
+    exit 1
+  fi
+fi
+
+CHANGE_LOG_YAML=$(mktemp)
+echo "[]" > "${CHANGE_LOG_YAML}"
+
+function map_type_to_kind() {
+  case "${1}" in
+    feat)
+      echo "added"
+    ;;
+    fix)
+      echo "fixed"
+    ;;
+    chore|style|test|ci|docs|refac)
+      echo "changed"
+    ;;
+    revert)
+      echo "removed"
+    ;;
+    sec)
+      echo "security"
+    ;;
+    *)
+      echo "skip"
+    ;;
+  esac
+}
+
+COMMIT_TITLES="$(git log --pretty=format:"%s" "${OLD_TAG}..${NEW_TAG}")"
+
+echo "INFO: Generate change log entries from ${OLD_TAG} until ${NEW_TAG}"
+
+while IFS= read -r line; do
+  if [[ "${line}" =~ ^([a-zA-Z]+)(\([^\)]+\))?\:\ (.+)$ ]]; then
+    TYPE="${BASH_REMATCH[1]}"
+    KIND=$(map_type_to_kind "${TYPE}")
+
+    if [ "${KIND}" == "skip" ]; then
+      continue
+    fi
+
+    DESC="${BASH_REMATCH[3]}"
+
+    echo "- ${KIND}: ${DESC}"
+
+    jq --arg kind changed --arg description "$DESC" '. += [ $ARGS.named ]' < ${CHANGE_LOG_YAML} > ${CHANGE_LOG_YAML}.new
+    mv ${CHANGE_LOG_YAML}.new ${CHANGE_LOG_YAML}
+
+  fi
+done <<< "${COMMIT_TITLES}"
+
+if [ -s "${CHANGE_LOG_YAML}" ]; then
+  yq --inplace --input-format json --output-format yml "${CHANGE_LOG_YAML}"
+  yq --no-colors --inplace ".annotations.\"artifacthub.io/changes\" |= loadstr(\"${CHANGE_LOG_YAML}\") | sort_keys(.)" "${CHART_FILE}"
+else
+  echo "ERROR: Changelog file is empty: ${CHANGE_LOG_YAML}" 1>&2
+  exit 1
+fi
+
+rm "${CHANGE_LOG_YAML}"
diff --git a/.gitea/workflows/release-version.yml b/.gitea/workflows/release-version.yml
index 7406a4a..6f2e9bc 100644
--- a/.gitea/workflows/release-version.yml
+++ b/.gitea/workflows/release-version.yml
@@ -5,33 +5,71 @@ on:
     tags:
       - "*"
 
-env:
-  # renovate: datasource=docker depName=alpine/helm
-  HELM_VERSION: "3.17.3"
-
 jobs:
   generate-chart-publish:
     runs-on: ubuntu-latest
     steps:
       - uses: actions/checkout@v4
-      - name: install tools
+        with:
+          fetch-depth: 0
+
+      - name: Determine Architecture and Operating System to support x86_64 and ARM based CI nodes
         run: |
-          apt update -y
-          apt install -y curl ca-certificates curl gnupg
-          # helm
-          curl -O https://get.helm.sh/helm-v${{ env.HELM_VERSION }}-linux-amd64.tar.gz
-          tar -xzf helm-v${{ env.HELM_VERSION }}-linux-amd64.tar.gz
-          mv linux-amd64/helm /usr/local/bin/
-          rm -rf linux-amd64 helm-v${{ env.HELM_VERSION }}-linux-amd64.tar.gz
+          # determine operating system
+          OS=$(uname | tr '[:upper:]' '[:lower:]')
+          echo "OS=${OS}" >> $GITHUB_ENV
+          echo "INFO: Set environment variable OS=${OS}"
+
+          # determine architecture
+          ARCH="$(uname -m)"
+          case "${ARCH}" in
+            aarch64) ARCH=arm64;;
+            x86_64) ARCH=amd64;;
+          esac
+          echo "ARCH=${ARCH}" >> $GITHUB_ENV
+          echo "INFO: Set environment variable ARCH=${ARCH}"
+
+      - name: Install packages via apt
+        run: |
+          apt update --yes
+
+          echo "INFO: Install packages via apt"
+          apt install --yes curl ca-certificates curl gnupg jq
+
+      - name: Install helm
+        env:
+          # renovate: datasource=docker depName=alpine/helm
+          HELM_VERSION: "3.17.3"
+        run: |
+          curl --fail --location --output /dev/stdout --silent --show-error https://get.helm.sh/helm-v${HELM_VERSION}-${OS}-${ARCH}.tar.gz | tar --extract --gzip --file /dev/stdin
+          mv ${OS}-${ARCH}/helm /usr/local/bin/
+          rm --force --recursive ${OS}-${ARCH} helm-v${HELM_VERSION}-${OS}-${ARCH}.tar.gz
           helm version
-          # docker
+
+      - name: Install yq
+        env:
+          YQ_VERSION: v4.45.4 # renovate: datasource=github-releases depName=mikefarah/yq
+        run: |
+          curl --fail --location --output /dev/stdout --silent --show-error https://github.com/mikefarah/yq/releases/download/${YQ_VERSION}/yq_${OS}_${ARCH}.tar.gz | tar --extract --gzip --file /dev/stdin
+          mv yq_${OS}_${ARCH} /usr/local/bin
+          rm --force --recursive yq_${OS}_${ARCH} yq_${OS}_${ARCH}.tar.gz
+          yq --version
+
+      - name: Install docker-ce via apt
+        run: |
+          echo "INFO: Install docker"
           install -m 0755 -d /etc/apt/keyrings
-          curl -fsSL https://download.docker.com/linux/ubuntu/gpg | gpg --dearmor -o /etc/apt/keyrings/docker.gpg
+          curl --fail --location --silent --show-error https://download.docker.com/linux/ubuntu/gpg | gpg --dearmor -o /etc/apt/keyrings/docker.gpg
           chmod a+r /etc/apt/keyrings/docker.gpg
           echo "deb [arch="$(dpkg --print-architecture)" signed-by=/etc/apt/keyrings/docker.gpg] https://download.docker.com/linux/ubuntu "$(. /etc/os-release && echo "$VERSION_CODENAME")" stable" | tee /etc/apt/sources.list.d/docker.list > /dev/null
-          apt update -y
-          apt install -y python3 python3-pip apt-transport-https docker-ce-cli
+          apt update --yes
+          apt install --yes python3 python3-pip apt-transport-https docker-ce-cli
+
+      - name: Install awscli
+        run: |
+          echo "INFO: Install awscli via python pip"
           pip install awscli --break-system-packages
+          aws --version
 
       - name: Import GPG key
         id: import_gpg
@@ -41,6 +79,15 @@ jobs:
           passphrase: ${{ secrets.GPGSIGN_PASSPHRASE }}
           fingerprint: CC64B1DB67ABBEECAB24B6455FC346329753F4B0
 
+      - name: Add Artifacthub.io annotations
+        run: |
+          NEW_TAG="$(git tag --sort=-version:refname | head --lines 1)"
+          OLD_TAG="$(git tag --sort=-version:refname | head --lines 2 | tail --lines 1)"
+          .gitea/scripts/add-annotations.sh "${OLD_TAG}" "${NEW_TAG}"
+
+      - name: Print Chart.yaml
+        run: cat Chart.yaml
+
       # Using helm gpg plugin as 'helm package --sign' has issues with gpg2: https://github.com/helm/helm/issues/2843
       - name: package chart
         run: |
@@ -51,7 +98,7 @@ jobs:
           helm package --version "${GITHUB_REF#refs/tags/v}" ./
           mkdir gitea
           mv gitea*.tgz gitea/
-          curl -s -L -o gitea/index.yaml https://dl.gitea.com/charts/index.yaml
+          curl --fail --location --output gitea/index.yaml --silent --show-error https://dl.gitea.com/charts/index.yaml
           helm repo index gitea/ --url https://dl.gitea.com/charts --merge gitea/index.yaml
           # push to dockerhub
           echo ${{ secrets.DOCKER_CHARTS_PASSWORD }} | helm registry login -u ${{ secrets.DOCKER_CHARTS_USERNAME }} registry-1.docker.io --password-stdin