LinuxXI · Package ManagementPackage management
Package management overview — apt vs dnf
What you'll learn
- Explain the role of a package manager
- Compare Debian-family (apt) and RHEL-family (dnf)
- Identify what a package contains
- Distinguish apt upgrade from apt full-upgrade and resolve kept-back packages
- Handle conffiles across an upgrade on both families, interactively and unattended
- Plan package management policy for a fleet
Prerequisites
None — start here.
Verified against Ubuntu 24.04 LTS · Debian 12 (Bookworm) · RHEL 9.x · Rocky Linux 9.x · AlmaLinux 9.x · Linux kernel 6.1 LTS / 6.6 LTS · systemd 255+ · OpenSSH 8.7p1 (RHEL 9) / 9.6p1 (Ubuntu 24.04) · nftables 1.0.x · chrony 4.x · Pacemaker 2.1.x · Corosync 3.1.x · 2026-08-11
A package manager is the system that installs, removes, queries,
and verifies the software on a Linux host. Manual installation
(tar -xzf, make install) bypasses the package manager and
produces unmaintainable, unauditable systems.
Why package managers exist
The original UNIX way was “compile from source”. Linux distributions replaced that with packages: pre-built binaries with metadata (name, version, dependencies, files, scripts). The package manager:
- Tracks every file installed by the package.
- Tracks dependencies between packages.
- Verifies package signatures before installation.
- Manages the upgrade path.
- Allows clean removal.
$ apt list --installed 2>/dev/null | head; dnf list installed 2>/dev/null | headaccountsservice/now 23.13.9-2ubuntu2 amd64 [installed,upgradable to: 23.13.10]
adduser/noble,now 3.137ubuntu1 amd64 [installed,local]
apparmor/noble,now 4.0.1-0ubuntu4 amd64 [installed,local]
...Illustrative output
The two main families
| Concern | Debian-family | RHEL-family |
|---|---|---|
| Package format | .deb | .rpm |
| Low-level tool | dpkg | rpm |
| High-level tool | apt / apt-get | dnf / yum |
| Repository config | /etc/apt/sources.list, /etc/apt/sources.list.d/ | /etc/yum.repos.d/ |
| Cache | /var/cache/apt/ | /var/cache/dnf/ |
| Query installed | dpkg -l or apt list --installed | rpm -qa or dnf list installed |
| Install | apt install <pkg> | dnf install <pkg> |
| Refresh metadata | apt update | implicit; dnf makecache to force |
| Upgrade, never removing | apt upgrade | no direct equivalent |
| Upgrade, removals allowed | apt full-upgrade (= apt-get dist-upgrade) | dnf upgrade |
| Align with the release | apt full-upgrade | dnf distro-sync |
| Remove | apt remove <pkg> or apt purge <pkg> | dnf remove <pkg> |
Most comparison tables collapse the upgrade rows into a single
apt update && apt upgrade versus dnf upgrade. That mapping
is wrong, and it is the wrong kind of wrong: the two commands
do different amounts of work. apt update only refreshes the
package lists and upgrades nothing. apt upgrade is more
conservative than dnf upgrade, not equivalent to it.
upgrade vs full-upgrade, and “kept back”
apt upgrade will never remove an installed package. If an
upgrade cannot be completed without removing something, apt
silently skips that package and reports it as held back:
The following packages have been kept back:
linux-generic linux-headers-generic linux-image-generic
0 upgraded, 0 newly installed, 0 to remove and 3 not upgraded.
apt full-upgrade performs the same job but is permitted to
remove packages in order to upgrade the system as a whole. It
is the same operation as the older apt-get dist-upgrade.
Neither command is “the safe one”. They trade different risks:
| Command | Removes packages? | The risk it carries |
|---|---|---|
apt upgrade | Never | Silently skips updates, including security fixes |
apt full-upgrade | Yes, when needed | May remove a package you needed, unattended |
Work out why a package is held back before you reach for
full-upgrade:
$ apt list --upgradable; apt-mark showhold; sudo apt-get -s dist-upgradeListing... Done
linux-generic/noble-updates 6.8.0-45.45 amd64 [upgradable from: 6.8.0-41.41]
...
The following packages will be REMOVED:
linux-image-6.8.0-41-generic
The following packages will be upgraded:
linux-generic linux-headers-generic linux-image-generic
3 upgraded, 3 newly installed, 1 to remove and 0 not upgraded.Illustrative output
The rule for a patching run: simulate with
apt-get -s dist-upgrade, read the removals, then run
apt full-upgrade with the removal list already understood.
An unattended full-upgrade on production, with nobody having
read the Remv lines, is how a monitoring agent disappears
during a patch window.
$ dpkg -l openssh-server 2>/dev/null; rpm -q openssh-server 2>/dev/nullDesired=Unknown/Install/Remove/Purge/Hold
| Status=not/known/ok | err?=(none)/Reinst-required...
|/ Err?=(none)/Reinst-required (Status,Err: uppercase=bad)
||/ Name Version Architecture Description
+++-==============-============-============-=================================
ii openssh-server 1:9.6p1-3ubun amd64 secure shell (SSH) server...
Illustrative output
What a package contains
A package is more than the binary. The metadata includes:
- Pre-install and post-install scripts (run by the package manager).
- Conffiles — configuration files the package manager tracks separately (so an upgrade does not overwrite your edits unless you choose to).
- Triggers — events that cause dependent actions (e.g., regenerating the initramfs after a kernel update).
- File list with permissions, owners, and checksums.
- Dependency declarations.
- Digital signature.
$ dpkg -L openssh-server 2>/dev/null | head; rpm -ql openssh-server 2>/dev/null | head/.
/usr
/usr/lib
/usr/lib/openssh
/usr/lib/openssh/sshd-keygen
/usr/lib/systemd
/usr/lib/systemd/system/sshd.service
/usr/sbin
/usr/sbin/sshd
...Illustrative output
Conffiles across an upgrade
A conffile is a configuration file the package manager tracks separately, so an upgrade does not blindly discard your edits. What happens when both you and the vendor changed the file depends on the packaging system.
| Situation | Debian (dpkg) | RHEL (rpm) |
|---|---|---|
| You did not edit it | Vendor version installed | Vendor version installed |
| You edited it, vendor changed it | Interactive prompt (keep, replace, diff, shell) | %config(noreplace): your file stays, vendor version written as <file>.rpmnew |
You edited it, vendor changed it, plain %config | n/a | Your file moved to <file>.rpmsave, vendor version installed |
Note what RPM does not do: it does not simply replace your
file. Most RHEL service configs, including
/etc/ssh/sshd_config, are marked %config(noreplace), so
your hardening survives and the vendor’s new options land in a
.rpmnew file that nobody reads unless you go looking.
Automated patching has to answer the Debian prompt in advance, or it will hang on a host with no terminal attached:
sudo DEBIAN_FRONTEND=noninteractive apt-get -y \
-o Dpkg::Options::=--force-confdef \
-o Dpkg::Options::=--force-confold upgrade
--force-confoldkeeps your existing file.--force-confdeflets dpkg take the default action where it has one, so the prompt never appears.--force-confnewis the opposite policy: take the vendor file, discard yours. Use it only where configuration is managed elsewhere, such as by Ansible or Puppet.
Then sweep for the files the upgrade could not merge. This belongs in every post-patch validation, on both families:
find /etc \( -name '*.dpkg-dist' -o -name '*.dpkg-old' \
-o -name '*.ucf-dist' \) 2>/dev/null
find /etc \( -name '*.rpmnew' -o -name '*.rpmsave' \) 2>/dev/null
Production discipline
- Pin package versions for production stability.
- Use a configuration-management tool to ensure all hosts have the same package set.
- Mirror repositories locally for offline and predictable installs.
- Verify package signatures (default in modern apt/dnf).
- Treat every kept-back package as an unapplied update, not a cosmetic message.
- Sweep
/etcfor.dpkg-dist,.dpkg-old,.rpmnewand.rpmsaveafter every patch run, and resolve each one. - Audit installed packages quarterly for unnecessary dependencies.
Knowledge check
Knowledge check · 6 questions
Q1. Which command queries the package database on a Debian-family host?
Q2. Manually installing software with `tar -xzf && make install` is acceptable for production.
Q3. Which of the following are correct package management practices? Select all that apply.
Q4. A patch run ends with '0 upgraded, 0 newly installed, 0 to remove and 7 not upgraded'. What is the correct conclusion?
Q5. What is the practical difference between `apt upgrade` and `apt full-upgrade`?
Q6. An Ansible run of `apt-get -y upgrade` across the fleet stalls on a handful of hosts with no output. Those hosts have hand-edited configs. What is happening, and what is the fix?
Passing score: 75%. Answers are checked in this browser.