Skip to content

Latest commit

 

History

118 Commits

Folders and files

NameName
Last commit message
Last commit date
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

apt.pkg.haus

APT archive for pkg.haus packages: current upstream releases, built from source for Debian stable, testing and unstable, on amd64 and arm64.

Using the archive

Fetch the signing keyring, then add the source - pick the suite matching your system (trixie, testing or unstable):

sudo curl -fsSL -o /usr/share/keyrings/pkghaus-archive-keyring.gpg \
    https://apt.pkg.haus/pkghaus-archive-keyring.gpg

sudo tee /etc/apt/sources.list.d/pkghaus.sources > /dev/null <<EOF
Types: deb
URIs: https://apt.pkg.haus
Suites: trixie
Components: main
Signed-By: /usr/share/keyrings/pkghaus-archive-keyring.gpg
EOF

sudo apt update
sudo apt install pkghaus-archive-keyring <package>

pkghaus-archive-keyring takes over the manually fetched trust anchor: key rotations then arrive as ordinary signed package updates, with no further manual step.

Versioning

One upstream release is built three times - once per suite, against that suite's libraries - so the version carries a suite qualifier instead of the filename:

Suite Example version
stable (trixie) 0.23.3-1~haus13+1
testing 0.23.3-1~testing1
unstable 0.23.3-1

The qualifiers order below the plain version (~haus13+1 < ~testing1 < 0.23.3-1), so upgrading your system from stable towards unstable upgrades these packages rather than fighting them. ~haus is this archive's own token, shaped after Debian's ~bpo backports convention but deliberately not squatting it - these packages do not come from Debian backports, and the token doubles as provenance in dpkg -l.

The archive carries one version per package per suite: each package's newest tag in packages. Older versions are rebuildable from their tags but not retained.

How it works

  • packages holds the packaging: one directory per package, each with a debian/ directory and a package.conf, built by action-debian-build's builder images. Its packages.txt is the enrolment list, and tags are namespaced by package (croc/v11.3.5-1).

  • Each validated release triggers the ingest, which compares each package's newest tag against the archive, builds only what is missing (natively per architecture, no emulation), and includes it into an aptly repository. Each build leg checks that tag out and runs the same action the packages repository runs on its own tags, so a package that ships debian/tests/ has those tests run here too. That matters: the archive builds a tag whenever it first needs it, sometimes weeks later, against whatever testing and unstable have become since.

  • Published pool files are immutable: the plan only ever adds missing versions, and a version already in the archive is never rebuilt.

  • dists/ and pool/ are objects in an R2 bucket, served through a Cloudflare Worker. The human-facing tree - the pool's listing pages, the news log, the keyring - lives on the archive branch and is served by the same Worker as static assets. Both answer under apt.pkg.haus; nothing is on GitHub Pages any more.

  • Every package publishes how it was built and what it was built from, at buildinfos.pkg.haus. `buildinfo-pool//

    /` holds dpkg's `.buildinfo`, naming every build dependency and its version, a `.source` naming the upstream commit and the compiler that ran, and the source package itself. A record is only ever published beside its `.dsc` and tarballs - alone it is useless, because `debrebuild` would fall back to debsnap, which has never heard of this archive. aptly cannot carry any of them - its pool is addressed by package identity - so they are written beside it rather than through it, the way Debian keeps buildinfos.debian.net separate from the archive. They are not on this host: the layout is a source pool, not an archive path, and the Worker here is the one that answers `apt update`.
  • Those records are what make the archive verifiable with debrebuild rather than only readable, and verify/rebuild.sh is the whole procedure. Given a .buildinfo, it resolves every build dependency from snapshot.debian.org at the versions recorded, unpacks the .dsc published beside it, rebuilds, and compares all four checksums:

    B=https://buildinfos.pkg.haus/buildinfo-pool/m/mandown
    mkdir mandown && cd mandown
    curl -fsSLO "$B/mandown_1.0.5.2-2~haus13+1_amd64.buildinfo"
    curl -fsSLO "$B/mandown_1.0.5.2-2~haus13+1.dsc"
    curl -fsSLO "$B/mandown_1.0.5.2-2~haus13+1.debian.tar.xz"
    curl -fsSLO "$B/mandown_1.0.5.2.orig.tar.gz"
    cd .. && verify/rebuild.sh mandown

    Proven end to end against a freshly published record: checking mandown_1.0.5.2-2~haus13+1_amd64.deb: size... sha256... md5... sha1... all OK, and the rebuilt .deb byte-identical to the one the archive serves.

  • The records are kept forever. So are the source tarballs, until the bucket approaches its budget: one generation across the fleet is 119 MB and additive growth is 836 MB a year, against a pool flat at 623 MB and a 10 GB free tier, so scripts/prune-source-tarballs.sh deletes nothing for the next several years. When it does, it goes oldest first and never touches a tarball a published version needs. A version leaving the pool is not the trigger: the .deb it describes is still installed on machines and still in apt caches, and that is exactly what a rebuild is checked against.

  • aptly's database lives on the aptly branch. Its package pool does not: at the bucket's root prefix aptly only reads a package file it cannot already find published, so each run keeps just what it built.

The archive Worker

worker/ is pkghaus-archive: pool/ and dists/ are objects in an R2 bucket that only it can read, so it is what makes apt.pkg.haus an archive rather than a bucket. It also writes the download counters, because it is the one point every download passes through.

It lives here rather than alongside the page that displays those counters because this is the repository that owns the archive: the same pipeline that publishes objects to the bucket deploys the thing that serves them.

The /stats page is a separate Worker in pkghaus/stats, reading the same database on a more specific route. Writer here, reader there, so a bad deploy of a page cannot take the archive down.

cd worker && npm ci && npm test

License

Copyright 2026 pkg.haus

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

   http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.

Buy us a coffee?

If you feel like buying us a coffee (or a beer?), donations are welcome:

BTC : bc1qq04jnuqqavpccfptmddqjkg7cuspy3new4sxq9
DOGE: DRBkryyau5CMxpBzVmrBAjK6dVdMZSBsuS
ETH : 0x2238A11856428b72E80D70Be8666729497059d95
LTC : MQwXsBrArLRHQzwQZAjJPNrxGS1uNDDKX6

About

Signed APT archive at apt.pkg.haus: aptly on R2, event-driven ingest, browsable index

Topics

Resources

Contributing

Security policy

Stars

2 stars

Watchers

0 watching

Forks

Contributors

Languages