Under the Hood of apt: How Debian Handles Your Software.
Today’s meeting will be on “Under the Hood of apt: How Debian Handles Your Software.” by me!
This is a comprehensive introduction to packages and package managers as a whole, but I chose to look at Debian to best explain things.
As usual, the meeting will be held in Sherman 103 at 7:15PM
You can see the presentation here:
While I was at it, I compiled my notes and made a writeup:
Packages and Package Managers
What is a system without software?
Nothing, really. Firmware only gets you so far.
So how do we install software? Well, you can always build it from source - pull the code, compile the binaries, add them to your path, configure everything. You might have even done this before:
./configure
make
make installThere’s gotta be a better way. Packages!!
What is a Package?
Think of it like a UPS delivery - a package is a packaged piece of software. Simple as that.
Packages are distributed as package archives. An archive is just a set of files bundled into a single container - not necessarily compressed. A package archive contains two things:
- Program Files - the files needed to install the program (not necessarily pre-compiled)
- Package Metadata - we’ll get to this
Package Archive Formats
No system like this is useful without some standardization. Many package archive formats have been defined across different systems and ecosystems. Some common ones:
.deb- Debian and derivatives (Ubuntu, etc.).rpm- Red Hat, Fedora, openSUSE.msi/.exe- Windows.apk- Android.pkg.tar.zst- Arch Linux.nixpkg- NixOSAppImage- Universal LinuxPUP/PET- Puppy LinuxFlatpak/Snap- Universal containerized formats
The .deb Format (Debian Package)
.deb files are the standard package format developed for Debian, and are used by its many derivatives like Ubuntu.
At its core, a .deb file is a ar archive - a simple archive format considered the predecessor to .tar. It contains three files:
pkg.deb (ar archive)
├── debian-binary # Text file with the package format version, e.g "2.0"
├── control.tar # Package metadata
└── data.tar # The actual installable filesInside control.tar
The control archive contains all the package metadata:
control- package description and dependenciesmd5sums- checksums of all files in the packageconffiles- marks config files that shouldn’t be overwritten on upgradepreinst,postinst,prerm,postrm- optional lifecycle scriptsconfig- optional script for debconfshlibs- shared library dependencies
The control file itself looks something like this:
Package: nano
Version: 8.7.1-1
Architecture: amd64
Maintainer: Jordi Mallach <jordi@debian.org>
Installed-Size: 2922
Depends: libc6 (>= 2.38), libncursesw6 (>= 6), libtinfo6 (>= 6)
Conflicts: pico
Description: small, friendly text editor inspired by PicoNote:
.debfiles technically support inline signature validation, but this is not commonly implemented. Debian instead handles trust at the repository level - more on that below.
Package Managers
Okay so we have packages. How do we actually manage them?
Package managers :)
Debian uses APT (Advanced Package Tool). APT is really just a high-level wrapper around DPKG.
DPKG - The Low Level Manager
DPKG (Debian Package) is the low-level tool actually responsible for installing and removing packages. You have to point it directly at a package archive:
dpkg -i nano.deb # Install a package
dpkg -r nano # Remove a package
dpkg -l # List installed packagesDPKG handles the installation itself and verifies file integrity using the md5sums from the control archive. But it’s limited - it doesn’t know how to fetch packages or resolve dependencies. That’s where APT comes in.
APT - Advanced Package Tool
APT builds on top of DPKG and adds:
- Dependency resolution - automatically pulls and installs all dependencies when you install a package
- Remote sources - can fetch package archives from configured repositories
APT pulls from repositories defined in /etc/apt/sources.list and /etc/apt/sources.list.d/. These can be remote mirrors or even local CD images.
apt update # Sync package indices from configured repos
apt upgrade # Compare local versions against index, upgrade as needed
apt install pkg-name # Search repos, fetch archive, install with depsDebian Repository Structure
A Debian repository is a structured directory. Here’s what it looks like:
dists/
└── bookworm/ # A release (also: trixie, stable, etc.)
├── release # Index of all Packages.gz files with their checksums
├── release.gpg # GPG signature of the release file
└── main/
└── binary-amd64/
└── Packages.gz # Index of all packages: metadata + file paths + checksums
pool/
└── main/
└── ... # Actual .deb files live hereWhen you run apt update, APT pulls the Packages.gz index for your release and architecture. This file contains the metadata and download path for every available package - including its checksum.
How APT Validates Authenticity
Trust is passed down through a chain of checksums:
- Updating - APT verifies the
Packages.gzintegrity against the checksum in thereleasefile - Pulling - APT verifies the downloaded
.debarchive against the checksum inPackages.gz - Installing - DPKG verifies the installed files against the
md5sumsinside the package archive itself
This is solid, but it all hinges on the release file being trustworthy in the first place.
Trusting the Root - GPG Signing
The release file is signed using asymmetric (public key) cryptography:
- A hash of the
releasefile is encrypted with Debian’s private key and stored asrelease.gpg- this is the digital signature - Your system decrypts that signature with Debian’s public key, computes its own hash of
release, and compares - if they match, the source is trusted
Since only the holder of the private key can produce a valid signature, this proves authenticity. The public key is typically distributed with the OS install image, so it’s already on your system when you set up. For new third-party repositories, you’ll need to manually add their key to /etc/apt/trusted.gpg.d/.
Other Package Managers
Most package managers follow the same general concepts as APT/DPKG - a low-level installer, a higher-level manager, and a repository structure with signed indices.
A few notable differences:
- Pacman / AUR (Arch Linux) - designed around distributing uncompiled packages; the AUR lets users publish build scripts rather than pre-built binaries
- DNF (Fedora/RHEL) / zypper (openSUSE) - RPM-based managers with similar repo and trust mechanisms to APT
- Flatpak, Snap, AppImage - a different philosophy entirely: built to run on any Linux system by bundling all dependencies inside a single container. The tradeoff is that they’re bloated, heavy, and inefficient compared to native system packages - but they solve the cross-distro compatibility problem.