Introduction
Developers who have modified open-source software know that modified packages need to be distributed for installation. The most efficient approach is to build a dedicated package repository, which integrates with system package managers and ensures timely updates. Examples are Arch Linux’s ArchCN and Debian’s PPA (Personal Package Archive).
Traditional repository setups often require complex tools or systems like Open Build Service (OBS). However, this guide focuses on lightweight methods suitable for distributing self-maintained packages.
While this article specifically covers Debian .deb
packages, the principles can be adapted to other package management systems.
Core Idea
Use reprepro
to create a software repository. After packaging your software, import it into the repository using reprepro
. Host the repository via HTTP (e.g., GitHub Pages) to make it publicly accessible.
Direct Method
GitHub Pages provides free static site hosting. You can host your repository as a Git repository on GitHub and use GitHub Pages to serve it. For setup details, refer to SetupWithReprepro. Below are the simplified repo setup steps using reprepro
:
Key Steps:
Generate a GPG signing key:
1
gpg --gen-key
Get the private key fingerprint (e.g.,
9FCD68DE8EFE8EC94ABEFDCB4FC5CF6FC16FDEF3
):1 2 3 4 5
$ gpg --list-secret-keys sign@example.com sec ed25519 2025-05-17 [SC] [expires: 2028-05-16] 9FCD68DE8EFE8EC94ABEFDCB4FC5CF6FC16FDEF3 uid [ultimate] Signing bot <sign@example.com> ssb cv25519 2025-05-17 [E] [expires: 2028-05-16]
Export the public key for users to verify signatures:
1
gpg --export --armor 9FCD68DE8EFE8EC94ABEFDCB4FC5CF6FC16FDEF3 > public.key
Create repository directories:
1 2
mkdir -p /path/to/your/repo mkdir -p /path/to/your/repo/conf
Configure
/path/to/your/repo/conf/distributions
:1 2 3 4 5 6 7 8 9
Codename: <release-name> Suite: <release-pseudonym> Architectures: source i386 amd64 <...> Components: main <...> Contents: SignWith: <fingerprint> Origin: <Your project name> Label: <Your project name> Description: <Your project description>
For configuration details, see Configure reprepro.
Create
/path/to/your/repo/conf/options
:1 2 3 4 5 6 7 8 9 10 11 12 13
cd /path/to/your/repo # Calling reprepro will behave normally at first... reprepro ... # ... set some default options ... cat > conf/options <<EOF verbose ask-passphrase EOF # ... now it acts like you called `reprepro --verbose --ask-passphrase`: reprepro ...
Build
.deb
packages.Add packages to the repository. Choose one from the following two methods according to your case.
Use
.changes
files:1
reprepro -b /path/to/your/repo include <release-name> <package>.changes
Use standalone
.deb
files:1
reprepro -b /path/to/your/repo includedeb <release-name> <package>.deb
Use
--ignore wrongdistribution
if package codename mismatches.Commit the repository to Git and push to GitHub.
Enable GitHub Pages for the repository branch. Users can then add your repository with:
|
|
Replace placeholders accordingly.
Workflow Method
The direct method works for small packages, but GitHub’s file size limits (100 MB/file) and Git LFS quotas make it impractical for large packages. Instead, use GitHub Actions to build and host packages dynamically via GitHub Pages.
Package Build Workflow Example
From Droidian Sony Pdx206 Kernel Repository:
|
|
This section uses the releng
build tool provided by Droidian (which I later discovered is part of the gbp/Git Build Package toolchain) for packaging. For regular Debian packages, you can also use dpkg-buildpackage
directly. The major difference between these two methods is that, releng
will use git informations as version name while dpkg-buildpacakge
will strictly follow the version name recorded in debian/changelog
. Signing during this stage is optional since packages will be signed together during repository import stage.
|
|
This step generates a directory listing page to display build artifacts when accessing the repository subpath directly.
Repository Build Workflow Example
This process is significantly simpler than manual repository setup thanks to the pre-existing morph027/apt-repo-action@v3.6 workflow. You only need to:
Configure essential parameters:
Set repository metadata in workflow environment variablesHandle cryptographic signing:
Store your private GPG key in GitHub Secrets (SIGNING_KEY
)Key distribution:
Export the public key using:1
gpg --export --armor [fingerprint] > public.key
Replace
fingerprint
with the actual one of your public key.
Workflow from ArchieMeng/custom-debs:
|
|
To properly use this workflow, you must configure these essential elements:
Workflow Environment Variables
1 2 3 4
env: CODENAME: trixie COMPONENTS: main ARCHITECTURES: "arm64"
Repository Secret Configure the GPG signing key via:
Project Settings > Security > Secrets and variables > Actions
- Secret name:
SIGNING_KEY
- Value: ASCII-armored GPG private key (export with
gpg --export-secret-keys -a <fingerprint>
)
- Secret name:
GitHub Pages Deployment Rules Update branch protection settings with
Project Settings > Environments > github-pages > Deployment branches
. Adjust deployment rules to match your workflow requirements:It should be like this:
Conclusion
These are the two methods I’ve used for setting up simple software repositories on GitHub. If you don’t need to distribute very large packages or lack a dedicated package build workflow, the first, simplest, and most direct method is suitable. However, if you’re like me and need to distribute large packages and have a complete build and distribution workflow, you might consider trying the second method, which is entirely workflow-based.
Naturally, these methods aren’t without their limitations. For instance, the process of managing packages within these self-hosted repositories doesn’t inherently handle inter-package dependencies. But for small repositories of this size, this situation typically isn’t a concern. :)