Linux Administration
Package Management
In this lesson
Package management is the system Linux uses to install, update, configure, and remove software in a controlled and repeatable way. Instead of downloading executables from websites, a package manager retrieves verified, pre-built software bundles from trusted repositories, resolves all dependencies automatically, and maintains a complete record of what is installed — making the entire software lifecycle auditable and reversible.
The Package Management Landscape
Linux package management splits into two major ecosystems based on distribution family. Debian-based systems (Ubuntu, Debian, Linux Mint) use .deb packages managed by apt and dpkg. Red Hat-based systems (RHEL, Rocky Linux, Fedora, AlmaLinux) use .rpm packages managed by dnf and rpm. Understanding both is essential for any professional Linux administrator.
Fig 1 — The two major Linux package ecosystems and their toolchains
Analogy: Think of apt and dnf as the app store on your phone — they find what you want, download it, and handle everything the app needs to work. dpkg and rpm are the installer underneath — they do the actual file placement, but won't go fetch missing dependencies for you.
apt — Package Management on Debian and Ubuntu
apt (Advanced Package Tool) is the primary interface for managing software on Debian-family systems. It works by fetching package metadata from repositories listed in /etc/apt/sources.list and /etc/apt/sources.list.d/, then resolving and installing dependencies automatically.
| Command | What it does |
|---|---|
apt update |
Refresh the local package index from all configured repositories. Does not install anything. |
apt upgrade |
Upgrade all installed packages to their latest available versions without removing any packages. |
apt full-upgrade |
Upgrade packages, and also remove or install packages as needed to satisfy dependencies. More aggressive than upgrade. |
apt install <pkg> |
Install a package and all its dependencies. |
apt remove <pkg> |
Remove a package but keep its configuration files on disk. |
apt purge <pkg> |
Remove a package and delete all its configuration files. |
apt autoremove |
Remove packages that were installed as dependencies but are no longer needed by anything. |
apt search <term> |
Search the package index for packages matching a name or description. |
apt show <pkg> |
Display detailed information about a package — version, size, dependencies, description. |
# The standard update-then-upgrade sequence — run this regularly
sudo apt update && sudo apt upgrade -y
# Install a package
sudo apt install nginx -y
# Install multiple packages at once
sudo apt install curl wget git vim -y
# Remove a package, keeping config files (useful if you plan to reinstall)
sudo apt remove nginx
# Purge a package and all its config files — clean removal
sudo apt purge nginx
# Remove orphaned dependency packages after a removal
sudo apt autoremove -y
# Search for packages by name or description
apt search "web server"
# Show full package details before installing
apt show nginx
# List all installed packages
dpkg --list
apt list --installed# apt show nginx
Package: nginx
Version: 1.24.0-2ubuntu7
Priority: optional
Section: web
Installed-Size: 854 kB
Depends: nginx-core (>= 1.24.0) | nginx-full (>= 1.24.0) | nginx-light (>= 1.24.0)
Homepage: https://nginx.net
Download-Size: 4,396 B
APT-Sources: http://archive.ubuntu.com/ubuntu noble/main amd64 Packages
Description: small, powerful, scalable web/proxy server
Nginx ("engine X") is a high-performance web and reverse proxy server
created by Igor Sysoev.
What just happened? apt show retrieved nginx's full metadata from the local package index — including its exact version, download size, dependency chain, and the repository it will be fetched from. This is the correct way to preview a package before installing it on a production system.
dnf and rpm — Package Management on RHEL and Rocky
dnf (Dandified YUM) is the modern package manager for Red Hat-based systems, replacing the older yum. Its command structure is intentionally similar to apt, making it straightforward to switch between distributions once you know either one.
apt (Debian / Ubuntu)
dnf (RHEL / Rocky / Fedora)
# Update package index and upgrade all packages (RHEL/Rocky)
sudo dnf check-update
sudo dnf upgrade -y
# Install a package
sudo dnf install nginx -y
# Install a package group (e.g. development tools)
sudo dnf groupinstall "Development Tools" -y
# Remove a package
sudo dnf remove nginx -y
# Search for a package
dnf search "web server"
# Show detailed package info
dnf info nginx
# List all installed packages
dnf list installed
# View transaction history — every install/remove/upgrade ever run
dnf history
# Undo the last transaction (rollback)
sudo dnf history undo last# dnf history
ID | Command line | Date and time | Action(s) | Altered
-------+----------------------+------------------+-------------+--------
5 | install nginx -y | 2025-03-12 10:22 | Install | 4
4 | upgrade -y | 2025-03-12 09:15 | Upgrade | 47
3 | install git curl -y | 2025-03-11 14:08 | Install | 6
2 | upgrade -y | 2025-03-10 08:00 | Upgrade | 12
1 | update -y | 2025-03-09 07:30 | I, U | 183
What just happened? dnf history showed a complete audit trail of every package operation on the system. This is a key operational advantage of dnf over apt — individual transactions can be reviewed and rolled back, making it possible to undo a bad upgrade without a full system restore.
Working with Repositories
A repository is a structured collection of packages hosted on a server that your package manager is configured to trust. Managing repositories — adding third-party sources, enabling or disabling them, and verifying their GPG keys — is a routine part of Linux administration.
Step 1 — Import the repository's GPG signing key
The GPG key allows your package manager to verify that packages from this repository have not been tampered with. Never add a repository without importing its key first.
# Debian/Ubuntu
curl -fsSL https://repo.example.com/gpg.key | sudo gpg --dearmor -o /etc/apt/keyrings/example.gpg
Step 2 — Add the repository source entry
Add a source line pointing to the repository URL, referencing the key you just imported.
# Debian/Ubuntu — write to a dedicated file in sources.list.d/
echo "deb [signed-by=/etc/apt/keyrings/example.gpg] https://repo.example.com stable main" | \
sudo tee /etc/apt/sources.list.d/example.list
Step 3 — Update the package index
Refresh the local index so the new repository's packages are visible to the package manager.
sudo apt update # Debian/Ubuntu
sudo dnf check-update # RHEL/Rocky
Step 4 — Install from the new repository
The package is now available just like any other. You can optionally pin to a specific version from this repo.
sudo apt install example-package -y
# List all currently configured repositories (Debian/Ubuntu)
cat /etc/apt/sources.list
ls /etc/apt/sources.list.d/
# List all enabled repositories (RHEL/Rocky)
dnf repolist
dnf repolist all # includes disabled repos
# Enable or disable a repo (RHEL/Rocky)
sudo dnf config-manager --enable epel
sudo dnf config-manager --disable epel
# Add the EPEL repository on RHEL/Rocky (common source for extra packages)
sudo dnf install epel-release -y
# Remove a third-party apt repository
sudo rm /etc/apt/sources.list.d/example.list
sudo apt update# dnf repolist repo id repo name appstream Rocky Linux 9 - AppStream baseos Rocky Linux 9 - BaseOS epel Extra Packages for Enterprise Linux 9 extras Rocky Linux 9 - Extras # cat /etc/apt/sources.list.d/docker.list deb [arch=amd64 signed-by=/etc/apt/keyrings/docker.gpg] https://download.docker.com/linux/ubuntu noble stable
What just happened? The Docker repository is a perfect real-world example of the correct pattern — its entry in sources.list.d/ explicitly references its own GPG key file via signed-by=, meaning packages from that repo can only be installed if they are signed by Docker's key. This is the modern, secure way to add third-party repositories.
Querying and Inspecting Packages with dpkg and rpm
While apt and dnf are used for installing and removing packages, the low-level tools dpkg and rpm are invaluable for querying exactly what is installed, which package owns a specific file, and what files a package contains.
Shows every package currently installed on the system with its version and status. Pipe through grep to search: dpkg -l | grep nginx
Essential for finding where a package put its config files, binaries, and man pages: dpkg -L nginx
Given any file path, returns the package that installed it: dpkg -S /usr/bin/curl. Extremely useful when troubleshooting.
Lists every installed package with version and release: rpm -qa | grep nginx
Same as dpkg -L but for RPM packages: rpm -ql nginx
Same as dpkg -S for RPM systems: rpm -qf /usr/bin/curl
# Find which package owns the curl binary (Debian/Ubuntu)
dpkg -S /usr/bin/curl
# Find which package owns a file (RHEL/Rocky)
rpm -qf /usr/bin/curl
# List every file installed by the nginx package (Debian/Ubuntu)
dpkg -L nginx
# List every file installed by the nginx package (RHEL/Rocky)
rpm -ql nginx
# Check if a specific package is installed (Debian/Ubuntu)
dpkg -l nginx | grep ^ii
# Check if a specific package is installed (RHEL/Rocky)
rpm -q nginx# dpkg -S /usr/bin/curl curl: /usr/bin/curl # rpm -qf /usr/bin/curl curl-7.76.1-26.el9_3.2.x86_64 # dpkg -l nginx | grep ^ii ii nginx 1.24.0-2ubuntu7 amd64 small, powerful, scalable web/proxy server # rpm -q nginx nginx-1.24.0-3.el9.ngx.x86_64
What just happened? dpkg -S and rpm -qf are invaluable during incident investigation — if a binary has been replaced or tampered with, these commands tell you which package originally installed it, so you can reinstall the package to restore the legitimate file.
Holding Packages and Version Pinning
In production environments, automatically upgrading every package on every apt upgrade can break applications that depend on a specific version. Holding (Debian) and version locking (RHEL) prevent a package from being upgraded until you explicitly release the hold.
# Hold a package at its current version (Debian/Ubuntu)
sudo apt-mark hold nginx
# Verify which packages are held
apt-mark showhold
# Release a hold to allow upgrades again
sudo apt-mark unhold nginx
# Install a specific version of a package (Debian/Ubuntu)
sudo apt install nginx=1.24.0-2ubuntu7
# Lock a package to its current version (RHEL/Rocky — requires versionlock plugin)
sudo dnf install dnf-plugin-versionlock -y
sudo dnf versionlock add nginx
# List all locked packages
sudo dnf versionlock list
# Remove a version lock
sudo dnf versionlock delete nginx# apt-mark showhold nginx postgresql-15 # sudo apt upgrade -y The following packages have been kept back: nginx postgresql-15 0 upgraded, 0 newly installed, 0 to remove and 2 not upgraded. # sudo dnf versionlock list Last metadata expiration check: 0:02:14 ago. nginx-1:1.24.0-3.el9.ngx.x86_64
What just happened? With the hold in place, apt upgrade ran successfully but silently skipped nginx and postgresql — reporting them as "kept back" rather than failing. This is the correct production pattern: run automated security updates across the whole system, while manually controlling upgrades for business-critical packages.
Never Run apt upgrade Without apt update First
Running apt upgrade without first running apt update upgrades packages against a stale index — you may install an outdated version of a package that has since received a critical security patch. Always run sudo apt update && sudo apt upgrade -y as a single chained command. Similarly, never pipe the install flag (-y) blindly on production systems without reviewing what will change — reserve -y for automated scripts where the scope is already controlled.
Lesson Checklist
apt, dnf) and low-level tools (dpkg, rpm), and know when to use each
apt update before apt upgrade, and I know the equivalent dnf commands for RHEL-family systems
sources.list.d/
dpkg -S / rpm -qf to find which package owns any file, and dpkg -L / rpm -ql to list all files a package installed
apt-mark hold or dnf versionlock to prevent uncontrolled upgrades on production systems
Teacher's Note
The dpkg -S and rpm -qf commands are used far less often than they should be. Whenever a binary behaves unexpectedly or you need to know where a config file came from, these commands answer the question in one second — make them part of your standard troubleshooting reflex.
Practice Questions
1. On a Debian/Ubuntu server, you need to install PostgreSQL 15, then ensure it is never accidentally upgraded during a routine apt upgrade. Write every command required, and explain how you would verify the hold is in place.
sudo apt update → sudo apt install postgresql-15 -y → sudo apt-mark hold postgresql-15. Verify with apt-mark showhold — postgresql-15 should appear in the list. During future apt upgrade runs it will be reported as "kept back".
2. A colleague reports that the binary at /usr/bin/ssh may have been replaced on a Rocky Linux server. Describe how you would use low-level RPM tools to identify which package owns that file and then reinstall the package to restore it to its original state.
rpm -qf /usr/bin/ssh — this returns the package name, e.g. openssh-clients-8.7p1-34.el9.x86_64. Then reinstall it to restore the original binary: sudo dnf reinstall openssh-clients -y. Verify the file is restored with rpm -V openssh-clients — no output means all files match the package database.
3. Explain the difference between apt remove and apt purge. In what scenario would you prefer remove over purge, and when would purge be the correct choice?
apt remove uninstalls the package binaries but keeps configuration files on disk. Use it when you plan to reinstall later and want to preserve your settings. apt purge removes the package and deletes all its configuration files. Use it for a clean removal — for example when decommissioning a service or switching to a different implementation.
Lesson Quiz
1. What is the key difference between apt upgrade and apt full-upgrade?
2. You run dpkg -S /etc/nginx/nginx.conf and get no output. What does this most likely indicate?
3. Why is it important to import a repository's GPG key before adding it to your package manager's source list?
Up Next
Lesson 14 — System Services and systemd
Managing, enabling, and troubleshooting system services using systemctl and journalctl