It's great when GitHub-hosted projects produce .deb packages in their release workflow1,
but GitHub has never bothered to make a GitHub project something you can add to your system's sources.list to get ongoing updates.
Here we aim to make it easy and affordable to make an apt-compatible repository for your releases.
sudo apt-get install --no-recommends dpkg-dev sq xz-utilsAnd Node.js v24 (LTS) with pnpm.
Import packages from your latest release:
gh-release-apt import owner/repo
If you want your repository to retain multiple versions,
do save the resulting pool/**/Packages files (to version control or a persistent filesystem) so this release's packages don't have to be downloaded again next time.
With your signing key in the SIGNING_KEY environment variable, run:
gh-release-apt assemble
Then deploy to your server—excluding the .deb files themselves.
The key feature we rely on is that apt will follow redirects. This means we can keep using standard GitHub Release asset hosting for the packages themselves— which is great, because we don't want the overhead of storing extra copies of them, GitHub keeps paying for the bandwidth, and the project's download analytics keep working.
GitHub Pages doesn't provide a way to configure redirects, but other hosts do offer this in their static web hosting features.2 There is, however, often a limit on the number of redirect rules. For that reason, we organize the repository's package pool so it's easy to map back to GitHub URLs with a single rule (instead of Debian's alphabetized structure).
No code from the target GitHub repository or its release assets is executed in the process of creating the package repository.
Assets named *.deb are downloaded and extracted, so if we ever get another arbitrary code execution exploit in a decompression routine,
that would run with access to your signing key and write permissions to both your git repository and package repository.
But anything able to add an asset to your GitHub Release probably has all that already.
The usual supply chain considerations apply for gh-release-apt. (As well as any other tools you use during deployment, e.g. wrangler.)
Debian and Ubuntu-based systems extend a lot of trust to package repositories.
System administrators are encouraged to use the pinning mechanism of APT Preferences to limit what third-party repositories are used for,
but this doesn't happen by default and the manual even discourages it for novices.
Users should assume that adding your repository to their system's sources will allow you (the repository owner) to run unrestricted code any time they install or upgrade any package,
even if the name of the package has nothing to do with your project.
This is not the only way to create a signing key, but if you don't have one already, this creates a minimal key for signing only.
sq key generate --without-password --can-sign --cannot-encrypt --cannot-authenticate --shared-key --no-userids
sq cert export --cert $FINGERPRINT | sq packet dearmor --output archive-keyring.pgp
sq key export --cert $FINGERPRINT | gh secret set SIGNING_KEYSee DebianRepository/UseThirdParty for recommendations on where to name and place the certificate.
Footnotes
-
Shoutout to GoReleaser and Tauri as a few tools I've seen enabling Debian packaging in the wild. ↩
-
including GitLab Pages, CloudFlare Workers Static Assets, AWS S3 or AWS Amplify, NearlyFreeSpeech, Firebase, Netlify, Vercel, Digital Ocean, Render, pico.sh, Codeberg, etc. ↩