Skip to content

Package Management (dnf & apt)

Almost everything you install on Linux comes from a package delivered through a repository. This page covers dnf and rpm on AlmaLinux 9 / RHEL 9, the apt/dpkg equivalents on Debian/Ubuntu, and how to keep a system patched.

Tested on

AlmaLinux 9.4 (dnf/rpm) and Ubuntu 22.04 LTS (apt/dpkg).

Packages vs repositories

  • A package is a single bundled archive of files plus metadata (name, version, dependencies). On RHEL-family systems these are .rpm files; on Debian-family systems they are .deb files.
  • A repository is a server-hosted collection of packages plus an index. Your package manager downloads the index, resolves dependencies, and pulls in everything needed.
  • dnf (and apt) are the high-level tools that talk to repositories and resolve dependencies. rpm (and dpkg) are the low-level tools that operate on individual package files already on disk — they do not resolve dependencies from the network.

RHEL / AlmaLinux: dnf

dnf is the default package manager on RHEL 8/9, AlmaLinux, Rocky, and Fedora. (yum still exists as a symlink to dnf for compatibility.)

Installing, removing, updating

# Install a package (and its dependencies)
sudo dnf install httpd

# Install without the yes/no prompt
sudo dnf install -y httpd

# Remove a package (leaves dependencies that other packages still need)
sudo dnf remove httpd

# Update a single package to the latest available version
sudo dnf update httpd

# Update EVERYTHING on the system (the most common patching command)
sudo dnf update

update vs upgrade on dnf

On dnf, update and upgrade are aliases — they do the same thing. (This differs from apt, where they are very different commands.) dnf upgrade is the modern preferred spelling.

Searching and inspecting

# Search package names and summaries for a keyword
dnf search nginx

# Show detailed info about a package (version, size, license, description)
dnf info httpd

# List installed packages, or available packages
dnf list installed
dnf list available
dnf list installed 'php*'      # glob match

# Which package provides a given file or command?
dnf provides /usr/sbin/httpd
dnf provides '*/semanage'      # find the package owning a missing command

Repositories

# List enabled repositories
dnf repolist

# List ALL repos including disabled ones
dnf repolist --all

Repository definitions live in /etc/yum.repos.d/ as *.repo files:

# /etc/yum.repos.d/example.repo
[example]
name=Example Repository
baseurl=https://repo.example.com/el9/$basearch/
enabled=1
gpgcheck=1
gpgkey=https://repo.example.com/RPM-GPG-KEY-example

Enable or disable a repo for a single command, or permanently:

# Use a disabled repo just for this transaction
sudo dnf install --enablerepo=crb some-package

# Skip a repo just for this transaction
sudo dnf update --disablerepo=epel

# Permanently enable/disable a repo
sudo dnf config-manager --set-enabled crb
sudo dnf config-manager --set-disabled epel

EPEL (Extra Packages for Enterprise Linux)

EPEL is a community repository with thousands of packages not shipped in the base RHEL repos (e.g. htop, fail2ban, nginx modules).

# Enable EPEL on AlmaLinux/Rocky/RHEL 9
sudo dnf install epel-release

# Some EPEL packages also need the CRB (CodeReady Builder) repo
sudo dnf config-manager --set-enabled crb

# Now EPEL packages are available
sudo dnf install htop

Package groups

Groups bundle related packages (e.g. a whole desktop or development toolset).

# List available groups
dnf group list

# See what a group contains
dnf group info "Development Tools"

# Install a group
sudo dnf group install "Development Tools"

History and undo

dnf records every transaction, and you can roll one back — extremely useful when an update breaks something.

# Show the transaction history
dnf history
ID     | Command line             | Date and time    | Action(s)      | Altered
-------------------------------------------------------------------------------
    14 | install nginx            | 2026-06-07 09:12 | Install        |    3
    13 | update                   | 2026-06-06 22:01 | Upgrade        |   47
    12 | install epel-release     | 2026-06-05 14:33 | Install        |    1
# Inspect what a specific transaction did
dnf history info 14

# Undo a transaction (reverse it)
sudo dnf history undo 14

# Redo a transaction
sudo dnf history redo 14

Cleaning the cache

# Remove cached package metadata and downloaded packages
sudo dnf clean all

# Rebuild the metadata cache
sudo dnf makecache

Low-level: rpm

rpm queries and operates on packages directly. It does not resolve dependencies — use dnf for installs. rpm is mainly for inspection.

# List ALL installed packages
rpm -qa

# Is a specific package installed?
rpm -qa | grep httpd
rpm -q httpd

# Detailed info about an installed package
rpm -qi httpd

# List all files a package installed
rpm -ql httpd

# Which package owns a given file? (q-uery the f-ile)
rpm -qf /etc/httpd/conf/httpd.conf
httpd-2.4.57-5.el9.x86_64

Mnemonic

-qa = query all, -qi = query info, -ql = query list of files, -qf = query owning file.


Debian / Ubuntu: apt

On Debian, Ubuntu, and derivatives, the high-level tool is apt and the low-level tool is dpkg.

# Refresh the package index (ALWAYS run this first — apt does NOT auto-refresh)
sudo apt update

# Upgrade installed packages, but never remove anything
sudo apt upgrade

# Upgrade, allowing packages to be removed/added if needed (kernel jumps, etc.)
sudo apt full-upgrade

# Install / remove / fully remove (incl. config files)
sudo apt install nginx
sudo apt remove nginx           # leaves config files behind
sudo apt purge nginx            # removes config files too

# Remove no-longer-needed dependencies
sudo apt autoremove

# Search and show
apt search nginx
apt show nginx

apt update is not apt upgrade

On Debian/Ubuntu these are completely different: apt update only refreshes the index of available versions; apt upgrade actually installs them. You must run update before upgrade or you'll install stale versions. (On dnf a single dnf upgrade does both.)

Low-level: dpkg

# List installed packages
dpkg -l
dpkg -l | grep nginx

# List files installed by a package
dpkg -L nginx

# Which package owns a file?
dpkg -S /usr/sbin/nginx

Adding repositories and PPAs

# Add an extra repository component, then refresh
sudo add-apt-repository universe
sudo apt update

# Add a PPA (Personal Package Archive — Ubuntu only)
sudo add-apt-repository ppa:deadsnakes/ppa
sudo apt update
sudo apt install python3.12

Repository definitions live in /etc/apt/sources.list and /etc/apt/sources.list.d/*.list (or modern .sources files). GPG keys typically live in /etc/apt/keyrings/.


dnf ↔ apt cheat sheet

Task dnf (RHEL/AlmaLinux) apt (Debian/Ubuntu)
Refresh index (automatic) apt update
Install dnf install pkg apt install pkg
Remove dnf remove pkg apt remove pkg
Remove + config dnf remove pkg apt purge pkg
Update everything dnf upgrade apt update && apt upgrade
Search dnf search term apt search term
Package info dnf info pkg apt show pkg
List installed dnf list installed / rpm -qa apt list --installed / dpkg -l
Files in a package rpm -ql pkg dpkg -L pkg
Which package owns a file rpm -qf /path dpkg -S /path
Clean unused deps dnf autoremove apt autoremove
List repos dnf repolist cat /etc/apt/sources.list*

Keeping a system patched

A patched system is your single biggest security win. A simple routine:

# AlmaLinux/RHEL — apply all security and bugfix updates
sudo dnf upgrade --refresh

# Apply ONLY security updates
sudo dnf upgrade --security

# Check whether a reboot is needed (e.g. after a kernel update)
dnf needs-restarting -r
# Ubuntu/Debian
sudo apt update && sudo apt full-upgrade

# Was a reboot required? (file exists = yes)
ls -l /var/run/reboot-required 2>/dev/null

Automate security patches

On RHEL/AlmaLinux install dnf-automatic to apply updates on a timer. On Ubuntu, unattended-upgrades does the same. Always test updates on a staging host before production, and ensure you have a rollback path (dnf history undo, snapshots, or backups).

Reboots and the kernel

dnf upgrade may install a new kernel, but you keep running the old one until you reboot. Schedule reboots for kernel and glibc updates. Manage which services restart automatically with care — see systemd Service Management.


Verify your work

# RHEL/AlmaLinux: confirm a package is installed and at the expected version
rpm -q httpd
dnf list installed httpd

# Confirm your repos are healthy
dnf repolist

# Confirm there are no pending updates (exit code 0 = up to date)
dnf check-update; echo "exit: $?"
# Debian/Ubuntu equivalents
dpkg -l nginx
apt list --upgradable

A patched system shows no pending updates and a clean dnf repolist with all expected repos enabled.

Summary

  • dnf (RHEL/AlmaLinux) and apt (Debian/Ubuntu) are high-level managers that resolve dependencies from repositories; rpm and dpkg are low-level tools for inspecting installed packages.
  • Install/remove/update with dnf install|remove|upgrade; search and inspect with dnf search|info|list|provides; manage repos with dnf repolist and config-manager.
  • dnf history lets you review and undo transactions — a lifesaver after a bad update.
  • Enable EPEL with dnf install epel-release (plus crb) for community packages.
  • On apt, always apt update before apt upgrade; use purge to drop config files and autoremove to clean orphans.
  • Keep systems patched regularly (dnf upgrade / apt full-upgrade), reboot for kernel updates, and consider automated security updates.

Test yourself