How to add packages to your local APT registry

Step-by-step guide to add your custom debian packages to your local APT registry


Problem Statement: Let's say I have a few custom packages that are modified versions of publicly available ones, like pcllib (point cloud library). If it were a standalone package, not dependent on any other packages, then it would be fine to just use dpkg. But because it requires other packages, it would be much easier to deal with dependencies if we could just use apt command. (Because debian package manager, APT, reads depends section on the package and resolves and installs dependencies for us when we run apt install ...).
How can I use apt install pcllib and download all dependent packages? That's when this guide would come in handy!

As the title shows, there are two parts to this tutorial:

  1. creating a meta-package
  2. creating a local apt registry

What is a 'meta-package'?

A 'meta-package' is a debian package that does not contain data but includes the meta data like dependencies that allows installations to be conducted.

In our case though, we will put *.deb packages into the meta package and register them to the local registry

How to setup local registry

When would you need to setup a local registry? Say, you have a modified version of a package, and you want to use the modified version (let's call it package_a_0.11.1-modified) instead. You can add this package to the local registry along with APT pinning to install this version instead of the one available on the remote registry. Then you can get all other dependencies resolved, while still being able to install your own version.
Note that the default behavior of apt is to install the highest version available.

There is already a helpful guide here on how to setup local registry, but I have detailed it in this post, too.

You need to first install dpkg-dev with the below command.

sudo apt install dpkg-dev

dpkg-dev includes the command we need dpkg-scanpackages

dpkg-scanpackages: what is it?

According to the man page, "dpkg-scanpackages sorts through a tree of Debian binary packages and creates a Packages file, used by apt, dselect, etc. to tell the user what packages a re available for installation. [...] You might use dpkg-scanpackages yourself if making a directory of local packages to install on a cluster of machines. Note: If you want to access the generated Packages file with apt, you will probably need to compress the file with bzip2 or gzip. apt ignores uncompressed Packages files except on local access".

We can derive what to do next from the man page.

First, you need to create a directory and put your debian packages there.

mkdir -p /etc/apt/local_packages

Then you need to create Packages.gz (or Packages.bz2, if using bzip2)

cd /etc/apt/local_packages
dpkg-scanpackages . /dev/null | gzip -9c > Packages.gz

You can also save the above as a script (e.g. update_local_packages), so that every time you update packages in /etc/aplt/local_packages, you can just run the script and update the apt registry like below:

sudo update_local_packages
sudo apt update

Now you need to tell package manager (APT) that you have new package sources by adding a new file, local_registry.list in /etc/apt/sources.list.d.

deb [trusted=yes] file:///etc/apt/local_packages ./

When you run apt update, Debian package manager reads /etc/apt/sources.list and all source files in /etc/apt/sources.list.d, and adds package sources to the repository (where it looks for a package, when you run commands like sudo apt install A).

How to install exact version from your package

When you define depends on your package, it automatically installs the newest version. However, if you want to use the exact version, you have to use what's called APT Pinning.

APT Pinning

You define your requirements in /etc/apt/preferences.d such as below:

Package: some_package_a
Pin: version 0.25.3~ubuntu.22.04~jammy
Pin-Priority: 1001

Note the Pin-Priority over 1000 is what it gives special priority.