Home / Alt manpages / dpkg-scanpackages(1)

  • dpkg-scanpackages(1)
  • User command
  • linux

Build a Debian Packages Index with dpkg-scanpackages

dpkg-scanpackages turns a directory of .deb files into the Packages index that APT actually reads. Get the relative path wrong and your repository quietly serves broken filenames. The examples use dpkg-scanpackages 1.22.6 from dpkg-dev 1.22.6ubuntu6.6, as installed on the machine used for this guide.

  • Time: about fifteen minutes.
  • You need: a shell, dpkg-dev, a directory of valid .deb files, and write access to where the index will be saved.
  • Privileges: the scan itself needs none. Writing into a system-owned repository, or installing packages, are separate operations that may.

1. Check the installed command

Start with read-only checks that confirm you are running the expected executable and see this installation's syntax:

$ command -v dpkg-scanpackages
/usr/bin/dpkg-scanpackages
$ dpkg-scanpackages --version
Debian dpkg-scanpackages version 1.22.6.
$ dpkg-query -W -f='${Package} ${Version}\n' dpkg-dev
dpkg-dev 1.22.6ubuntu6.6

The command takes a binary package tree, an optional override file, and an optional path prefix. Output goes to standard output, so the usual pattern is a shell redirection into a file:

$ dpkg-scanpackages BINARY_PATH > Packages

Checkpoint

Do not go further until command -v finds the command and its version output looks plausible for the host you are maintaining.

2. Put packages under a stable archive root

Decide the directory layout before scanning anything. For a small local archive, this is enough:

$ mkdir -p "$HOME/local-debian/pool"
$ cp /path/to/your-package.deb "$HOME/local-debian/pool/"
$ find "$HOME/local-debian" -type f -name '*.deb' -print
/home/you/local-debian/pool/your-package.deb

Swap in real paths for both placeholders. The command searches the binary path as a tree, so subdirectories are fine, and it normally only picks up files ending in .deb. A renamed archive will not pass as a valid Debian binary package.

Run the scanner from the archive root and pass the package directory as a relative path:

$ cd "$HOME/local-debian"
$ dpkg-scanpackages pool > Packages

That relative path is exactly what ends up in the Filename fields of the generated index. Scan an absolute directory instead and you get absolute-looking filenames, a poor fit for a repository whose files are served or copied from a different root. Read the result before wiring it into APT:

$ sed -n '1,24p' Packages
Package: your-package
Version: 1.0
Architecture: all
Filename: pool/your-package_1.0_all.deb
Size: 1234
MD5sum: ...
SHA1: ...
SHA256: ...

Fields and values depend on the package, but the filename should always point from the archive root to the package, and the size and hashes should describe the file actually sitting there.

3. Choose the generated hashes deliberately

By default the command generates every currently supported hash. Restrict that with -h or --hash. For a compact modern index, request only SHA-256:

$ dpkg-scanpackages --hash sha256 pool > Packages
$ awk '/^(MD5sum|SHA1|SHA256):/ {print}' Packages
SHA256: ...

The supported values in this version are md5, sha1, and sha256. Pass a comma-separated list when a consumer needs more than one:

$ dpkg-scanpackages --hash sha1,sha256 pool > Packages

Tip

A hash selection is not repository signing. These fields let a client verify the downloaded content, not who controls the repository. Any repository exposed to machines you do not fully control still needs a proper APT signing and key-distribution design.

4. Understand duplicate versions

Find more than one version of a package in the tree, and the default output keeps only the newest. If matching versions differ only by architecture, the first one found wins. That default suits a simple repository, but it can also hide an old package you expected to see.

Check package names and versions before scanning anything assembled automatically:

$ dpkg-deb -f pool/*.deb Package Version Architecture
Package: your-package
Version: 1.0
Architecture: all

Use --multiversion when the index has to contain every version found:

$ dpkg-scanpackages --multiversion pool > Packages
$ awk '/^(Package|Version):/ {print}' Packages

Checkpoint

Verify the entry count and versions match your policy. Do not reach for --multiversion just because it sounds safer; multiple versions can make repository selection murkier for clients and operators alike.

5. Add an override file only when you need one

The optional override file supplies distribution metadata such as a package's section and priority. Its format is defined by deb-override(5), not the same as a Debian control file. Use it when the repository's classification needs to differ from the package metadata:

$ dpkg-scanpackages pool path/to/override-file > Packages

Override files may be compressed on this and other supported dpkg versions. Skip the argument entirely if you have no deliberate override policy. The scanner warns about packages missing from an override file, and about maintainer substitutions that never took effect, so read the warnings rather than treating the finished file as proof every rule applied.

The --extra-override FILE option reads supplementary overrides in the format documented by deb-extra-override(5), another metadata input, not a replacement for the ordinary override-file position.

6. Check warnings and refresh the index safely

Capture diagnostics separately while writing the new index into a temporary file in the same repository directory:

$ tmp_packages="$(mktemp Packages.XXXXXX)"
$ if dpkg-scanpackages --hash sha256 pool > "$tmp_packages"; then
>     mv "$tmp_packages" Packages
> else
>     status=$?
>     rm -f "$tmp_packages"
>     exit "$status"
> fi
dpkg-scanpackages: info: Wrote 1 entries to output Packages file.

The informational line goes to standard error while the index itself lands on standard output. The entry count is a useful sanity signal, not a substitute for checking paths and versions. A failed scan leaves the temporary file removed and the previous Packages untouched, so recovery is simple: rerun the scan, or restore from your repository backup if a successful scan somehow used the wrong tree.

Warnings can flag wrong subdirectories, duplicate packages, an existing Filename control field, missing override entries, or maintainer substitutions that did nothing. Fix the layout or metadata source and regenerate. Do not silence warnings by redirecting all diagnostics away during a release build.

7. Compress the index for APT

APT generally ignores an uncompressed Packages file for remote repositories. Local file:// sources can use it uncompressed, per the manpage, but a compressed index is still the safer default for anything served:

$ gzip -c Packages > Packages.gz
$ xz -c Packages > Packages.xz
$ ls -l Packages Packages.gz Packages.xz

Keep the uncompressed file around while checking the result, then publish the compressed file or files alongside it, matched to the clients you support. These commands overwrite named outputs, so confirm you are in the intended repository directory before running them. A bad compressed file just means rerunning the command from the known-good Packages; no package installation is involved anywhere in this.

Done means

  • Versions recorded. dpkg-scanpackages --version and the dpkg-dev package version.
  • The scan used a relative binary path, producing usable Filename values.
  • Entry count, versions, architectures and warnings all checked. Not just skimmed.
  • Hash selection matches your clients and policy.
  • The new index only replaced the old one after a successful scan.
  • A compressed index is ready for any client that is not purely local.