2 of 4

Software ManagementLesson 2 of 4

Installing, updating and removing software with DNF

Search, install, update and remove packages and groups, install a local RPM with its dependencies, and undo a change.

  • dnf
  • dnf install
  • dnf remove
  • dnf upgrade
  • dnf search
  • dnf info
  • dnf provides
  • dnf group
  • dnf history
  • dnf download

45 min6 exercises

After this lesson you can

  • Find, install, update and remove packages, and read what DNF is about to do before confirming.
  • Install a local RPM file so its dependencies come from the repositories.
  • Work with package groups, review the transaction history and undo a transaction.

The idea

rpm installs a package file and stops. DNF is the package manager on top: it reads repositories (catalogues of packages), works out dependencies, downloads everything needed and installs it as one transaction that it records in a history. On RHEL 10 the dnf command is DNF 4, and yum is kept as an alias.

The daily commands:

TaskCommand
Find by name or descriptiondnf search keyword
Which package provides a file or commanddnf provides '*/name'
Details of a packagednf info name
Installdnf install name...
Install from a local filednf install ./file.rpm
Removednf remove name
List updatesdnf check-update
Update one package / everythingdnf upgrade name / dnf upgrade
Packages installed / availablednf list installed / dnf list available
Groupsdnf group list, dnf group install "Name"
Historydnf history, dnf history info N, dnf history undo N

Before DNF acts it prints the transaction summary: what will be installed, upgraded or removed, and how large the download is. Read it. -y answers yes to the question, which is right in scripts and in a hurry, but then nothing stops you removing 40 packages by mistake. Removing a package also removes anything that depends on it, and dnf remove shows those too.

Try it

dnf provides '*/bin/tree'
tree-2.1.0-6.el10.x86_64 : File system tree viewer
Repo        : rhel-10-for-x86_64-appstream-rpms
Matched from:
Filename    : /usr/bin/tree
sudo dnf install -y tree
rpm -q tree
sudo dnf remove -y tree
Installed:
  tree-2.1.0-6.el10.x86_64
Complete!
tree-2.1.0-6.el10.x86_64
Removed:
  tree-2.1.0-6.el10.x86_64
Complete!

Install a downloaded file the safe way

mkdir -p ~/lab/rpms && cd ~/lab/rpms
dnf download tree
sudo dnf install -y ./tree-*.rpm
tree-2.1.0-6.el10.x86_64.rpm            1.2 MB/s |  56 kB     00:00
Installed:
  tree-2.1.0-6.el10.x86_64
Complete!

Updates

dnf check-update; echo "exit=$?"
dnf updateinfo list security | head -3
kernel.x86_64            6.12.0-55.14.1.el10_0       rhel-10-for-x86_64-baseos-rpms
tzdata.noarch            2025b-1.el10                rhel-10-for-x86_64-baseos-rpms
exit=100
RHSA-2026:1234 Important/Sec. openssl-3.2.2-1.el10_0.x86_64
RHSA-2026:1250 Moderate/Sec.  tzdata-2025b-1.el10.noarch

dnf check-update exits 100 if updates exist, 0 if none, 1 on error, which is handy in scripts. dnf upgrade with no name updates everything; keep a kernel or two (installonly_limit=3 in /etc/dnf/dnf.conf) so you can boot the old one if the new one fails. A new kernel only runs after a reboot.

Groups and history

dnf group list | head -6
sudo dnf group install -y "Development Tools"
Available Environment Groups:
   Server with GUI
   Server
   Minimal Install
Available Groups:
   Development Tools
   Container Management
dnf history | head -4
sudo dnf history undo 12
ID     | Command line                        | Date and time    | Action(s)      | Altered
--------------------------------------------------------------------------------------
    12 | install -y tree                     | 2026-11-03 10:41 | Install        |    1
    11 | upgrade -y tzdata                   | 2026-11-03 10:20 | Upgrade        |    1

Going further

dnf install --downloadonly fetches without installing. dnf autoremove deletes packages that were only installed as dependencies and are no longer needed. dnf repoquery --requires NAME and dnf repoquery --whatrequires NAME show dependency relationships. dnf needs-restarting -r tells you if a reboot is needed after updates, and dnf versionlock pins a package at a version. DNF logs to /var/log/dnf.log and /var/log/dnf.rpm.log, the first place to look when a transaction fails.

Practice

0 of 6 done

Do these on your own system. They get harder. Check each result, then tick it off.

  1. Warm-up

    Find a package and read about it

    Search the repositories for a package that provides the tree command, show its details and say which repository it comes from.

    Check your result

    dnf info tree shows Name, Version, Repository (for example rhel-10-for-x86_64-appstream-rpms or appstream) and Summary.

    Hint

    dnf search tree, dnf info tree, or dnf provides /usr/bin/tree.

    Solution
    dnf search tree | head
    dnf info tree
    dnf provides /usr/bin/tree
  2. Practice

    Install, use, remove

    Install tree non-interactively. Confirm with rpm -q. Remove it and confirm it is gone. Explain what -y does and why you should read the transaction summary first when not using it.

    Check your result

    rpm -q tree shows a version after install, and package tree is not installed after removal.

    Hint

    sudo dnf install -y tree, sudo dnf remove -y tree.

    Solution
    sudo dnf install -y tree
    rpm -q tree
    tree -L 1 /etc | head -5
    sudo dnf remove -y tree
    rpm -q tree
  3. Practice

    Install a downloaded RPM file

    Download the RPM for tree into ~/lab/rpms (dnf download), then install from the file using DNF so that any dependencies would be resolved from the repositories. Do not use rpm -ivh. Remove it again.

    Check your result

    rpm -q tree shows it installed after sudo dnf install ./tree-*.rpm.

    Hint

    Give dnf install a path that contains a slash, like ./file.rpm; otherwise it searches repositories for a package of that name.

    Solution
    mkdir -p ~/lab/rpms && cd ~/lab/rpms
    dnf download tree
    sudo dnf install -y ./tree-*.rpm
    rpm -q tree
    sudo dnf remove -y tree
  4. Practice

    See what needs updating

    List the packages for which updates are available, show only security updates, then update a single package (tzdata or any package that is listed) without touching the rest of the system.

    Check your result

    dnf check-update exits with 100 when updates exist. dnf upgrade -y tzdata changes only that package (and anything it requires).

    Hint

    dnf check-update, dnf updateinfo list security, dnf upgrade PACKAGE.

    Solution
    dnf check-update; echo "exit=$?"
    dnf updateinfo list security | head
    sudo dnf upgrade -y tzdata
  5. Practice

    Install a group, then see it as a set

    List the available package groups, show which packages are in the Development Tools group, and install the mandatory and default members of that group. Afterwards remove the group again.

    Check your result

    dnf group list shows Development Tools. dnf group info 'Development Tools' lists members. After install gcc --version works; after removal rpm -q gcc says not installed (unless something else needs it).

    Hint

    Quote group names that contain a space. dnf group install "Development Tools" and dnf group remove.

    Solution
    dnf group list
    dnf group info "Development Tools"
    sudo dnf group install -y "Development Tools"
    gcc --version | head -1
    sudo dnf group remove -y "Development Tools"
  6. Challenge

    Undo a change

    Install tree, find that transaction in the history, show what it did, and undo it. Then identify, from the history alone, who ran the very first transaction on this machine and when.

    Check your result

    dnf history lists the install with an ID. dnf history info ID shows Packages Altered with tree. After sudo dnf history undo ID the package is removed.

    Hint

    dnf history, dnf history info N, dnf history undo N. The last entry in the list is the oldest.

    Solution
    sudo dnf install -y tree
    dnf history | head -4
    id=$(dnf history | awk 'NR>2 {print $1; exit}')
    dnf history info "$id"
    sudo dnf history undo -y "$id"
    rpm -q tree
    dnf history | tail -3