Simple local apt repository

It is often desirable to set up a local apt repository in which to store custom versions of Debian (or Ubuntu, etc) packages so that they can fall under the auspices of apt-get and friends just like the standard ones do, instead of managing them by hand with dpkg and the like. That way all the neat package management stuff works and you can do useful things like tell your system to prefer local versions of packages over the standard ones so they don't all get wiped out when you upgrade or install new stuff.

There is lots of official documentation out there about doing this but it does rather tend to make it look more complicated than it actually is. So here is a method of doing it which does the minimum necessary to create a pukka repository that lets all the cool stuff work but is no more complicated than it needs to be; it just does one architecture, one branch, one of more or less all the things that there might be more than one of.

The structure of the repository is like this:

/usr/local/custom-pkgs/ \__dists/ | \__local/ | \__main/ | | \__binary-i386/ | | \__Packages.gz | \__Release \__pool/ \__a/ | \__anaplasmosis.deb | \__arfle.deb | \__... \__b/ \__... \__liba/ | \__libanaplasmosis1.deb | \__libanaplasmosis-dev.deb | \__... \__libb/ \__... \__libz/ \__... \__z/ \__zonulesofzinn.deb

...which will probably look familiar if you've ever poked around the directory tree of an official repository :)

The two special files, Packages.gz and Release, are very easy to make. dpkg-scanpackages will scan the directory tree and create Packages, while Release is just a simple text file of which an example is given below (as part of the script). They are both extensively documented elsewhere and I can't be arsed with reproducing all that here since there's not a lot of point.

So, to set this up... You will need this line in /etc/apt/sources.list - as the first line, before all the other entries; order of lines in /etc/apt/sources.list is significant and this needs to come first if preferring local packages over standard ones is to work properly:

deb [trusted=yes] file:///usr/local/custom-pkgs local main

The [trusted=yes] bit is necessary to avoid having to frig around signing all the local packages, since we're after keeping it all as simple as possible.

An entry in /etc/apt/preferences is also needed:

Package: * Pin: release n=local Pin-Priority: 800

Without going into a detailed explanation of pinning - which again is extensively documented elsewhere - the Pin-Priority: 800 value doesn't have to be 800; anything between 501 and 999 inclusive will work the same way if you don't have any other pins defined. If you do, then you can more than likely work out a suitable value just as you did for what you have already...

You will also need to create the directory for the local repository - this document uses /usr/local/custom-pkgs - and give yourself write permissions to it. No need to worry about creating any of the subdirectories, just the top level one is enough.

Finally, you need this script - update-custom-pkgs - which will read your custom packages, copy them into the repository (creating directories as necessary), and update the Packages.gz and Release files.

#!/bin/bash PKGDIR="/usr/local/custom-pkgs" DISTS="dists/local/main/binary-i386" POOL="pool" if [ -z "$1" ]; then echo "No arguments supplied" exit 1 fi if [ "$1" == "-h" ] || [ "$1" == "--help" ] || [ "$1" == "-?" ] ; then echo "Usage: $(echo $0 | sed -e 's/^.*\///') package.deb [package.deb...]" echo " Copies package.deb to local repository $PKGDIR" echo " and updates repository's metadata." exit 0 fi while ! [ -z "$1" ]; do if ! file "$1" | grep 'Debian binary package' > /dev/null; then echo "$1 is not a Debian binary package - aborting" exit 1 fi f=$(echo "$1" | sed -e 's/^.*\///') d=$(echo "$f" | sed -n -e 's/^\(lib[a-z]\).*$/\1/p') [ -z "$d" ] && d=$(echo "$f" | sed -n -e 's/^\([a-z]\).*$/\1/p') dest="$PKGDIR/$POOL/$d" mkdir -p "$dest" || exit 1 cp "$1" "$dest" || exit 1 shift done cd "$PKGDIR" mkdir -p "$DISTS" || exit 1 cat > "$DISTS/../../Release" << EOF Origin: Local Label: Debian local Suite: local Codename: local Components: main Architectures: i386 EOF dpkg-scanpackages -m "$POOL" | gzip -9c > "$DISTS/Packages.gz" echo "You must now run \"apt-get update\" to make the new packages available."

Run that script on your custom packages - update-custom-pkgs arfle.deb barfle.deb gloop.deb or whatever - and then run apt-get update so the package management system knows the local packages are available. (Also do these two things whenever you have any new custom packages to add to the repository.)

And that's it!




Back to Pigeon's Nest


Be kind to pigeons




Valid HTML 4.01!