This article is heavily influenced by these existing articles.

The goal here is to create a static hosted website that can act as a repository for use with Arch Linux. For this purpose I primaily use two scripts.

generate-key.sh is a bash script used to generate a GPG key for the sake of signing my packages.

#!/usr/bin/env bash

set -e

script_dir=$( cd -- "$( dirname -- "${BASH_SOURCE[0]}" )" &> /dev/null && pwd )

if gpg --export --armor -a "MY NAME (Archlinux Private Package Repo)" |& grep 'gpg: WARNING: nothing exported'
then
	gpg --pinentry-mode=loopback --batch --gen-key --passphrase '' <<EOF
Key-Type: 1
Key-Length: 2048
Subkey-Type: 1
Subkey-Length: 2048
Name-Real: MY NAME (Archlinux Private Package Repo)
Name-Email: MY_USERNAME@users.noreply.github.com
Expire-Date: 0
EOF
fi

gpg --armor --export "MY NAME (Archlinux Private Package Repo)" > "./my-repository-key.gpg"

build.sh is a bash script used to walk a directory of packages and build them all automatically. Note PKGDEST would publish all the packages to ./docs, which is helpful when publishing to GitHub Pages. This path can be changed.

#!/usr/bin/env bash

set -e

script_dir=$( cd -- "$( dirname -- "${BASH_SOURCE[0]}" )" &> /dev/null && pwd )

# Update this as needed
gpg --import "${HOME}/my-repository-key.gpg"

# tail -1 to get the subkey, which is what ends up used for signing
key_id="$(gpg --list-keys --with-colons 'MY NAME' | awk -F: '$1=="fpr" { print $10 }' | tail -1)"

# Publish the
export PKGDEST="${script_dir}/docs"
export GPGKEY="${key_id}"
export PACKAGER="MY NAME <MY_USERNAME@users.noreply.github.com>"

rm -f "${PKGDEST}/my-repository.db.tar.gz"
rm -f "${PKGDEST}/my-repository.files.tar.gz"
find "${PKGDEST}" -type f -name "*.sig" -delete

# Iterate over package directories prefixed by 'my-package-'
for package_path in "${script_dir}"/my-package-*
do
	namcap "${package_path}/PKGBUILD"

	package_name="$(basename "${package_path}")"
	echo "${package_name} ${package_path}"

	# Use yay for aur resolutions? https://www.reddit.com/r/archlinux/comments/jj15c5/comment/gaanf7x/?context=3
	# --nodeps for meta/virtual packages with no real build steps.
	pushd "${package_path}"
		makepkg -f --nodeps --sign
	popd

	package_output_path="$(ls "${PKGDEST}/${package_name}"*.pkg.tar.zst)"

	namcap "${package_output_path}" | grep 'E:' || true
done

repo-add --key "${key_id}" --verify --sign "${PKGDEST}/my-repository.db.tar.gz" "${PKGDEST}/"*.pkg.tar.zst

Supporting files, helper scripts, and other data can also be copied to the output directory as needed. Be careful not to accidentally publish any sensitive scripts or information

The client can be configured like so. See here for an entry that could be added to /etc/pacman.conf.

[my-repository]
Server = https://my-repository.my-domain.com

Use --overwrite to indicate that we are explicitly overriding a system config file if necessary.

pacman --overwrite "*" -Syy <the package>