--- title: "Linux Package Management with APT, YUM and DNF" description: "Learn to install, update, search, hold and remove packages with APT on Ubuntu and DNF on Rocky Linux, add signed repositories and fix common package errors." category: "Operating Systems" language: en source: https://cubepath.com/docs/operating-systems/package-management-apt-yum-dnf updated: 2026-09-25 --- # Linux Package Management with APT, YUM and DNF A package manager installs software together with its dependencies, keeps it updated from signed repositories and removes it cleanly. Debian and Ubuntu use APT with `.deb` packages, while Red Hat Enterprise Linux, Rocky Linux and AlmaLinux use DNF with `.rpm` packages; YUM is DNF's predecessor. This guide shows the everyday tasks side by side on Ubuntu 24.04 and Rocky Linux 9: updating, installing, searching, holding versions, adding third-party repositories, undoing changes and fixing common errors. ## Prerequisites To follow along you need: - A server running Ubuntu 24.04 LTS (or Debian 12/13) and/or Rocky Linux 9 or AlmaLinux 9, for example a CubePath VPS. - A non-root user with `sudo` privileges. ## How APT, YUM and DNF relate | | Debian, Ubuntu | RHEL, Rocky Linux, AlmaLinux | |---|---|---| | Package format | `.deb` | `.rpm` | | High-level tool (resolves dependencies, uses repositories) | `apt` (also `apt-get`, `apt-cache`) | `dnf` (`yum` on EL7 and older) | | Low-level tool (single package files, database queries) | `dpkg` | `rpm` | | Repository configuration | `/etc/apt/sources.list.d/` | `/etc/yum.repos.d/` | | Automatic updates | `unattended-upgrades` | `dnf-automatic` | On Rocky Linux and AlmaLinux 8 and later, `yum` is only a compatibility link to `dnf`, so old `yum` commands keep working with the same syntax. You only meet the original YUM on CentOS 7 and other EL7 systems, which are end of life. This guide uses `dnf` throughout. `apt` is the command meant for interactive use. `apt-get` and `apt-cache` do the same jobs with an output format that stays stable between versions, so prefer them in scripts. ## Step 1 - Refreshing package information and updating the system APT keeps a local copy of the package lists and needs to refresh it before installing or upgrading. `apt upgrade` then installs newer versions of installed packages: ```bash sudo apt update sudo apt upgrade ``` ```output ... 42 packages can be upgraded. Run 'apt list --upgradable' to see them. ``` `apt upgrade` never removes packages. When an update needs to remove or replace a package (common with kernel and major library updates), use `full-upgrade` instead: ```bash sudo apt full-upgrade ``` DNF refreshes metadata automatically when it is older than its cache lifetime, so a single command lists and applies updates: ```bash sudo dnf check-update sudo dnf upgrade ``` On both families, a kernel update only takes effect after a reboot. Ubuntu creates `/var/run/reboot-required` when one is needed. On Rocky Linux, the `needs-restarting` command from the `dnf-utils` package tells you: ```bash sudo dnf install dnf-utils sudo needs-restarting -r ``` ```output Core libraries or services have been updated since boot-up: * kernel Reboot is required to fully utilize these updates. ``` ## Step 2 - Searching for packages and reading their details Search package names and descriptions: ```bash apt search redis ``` ```bash dnf search redis ``` Show the version, repository, size, dependencies and description of a package before installing it: ```bash apt show redis-server ``` ```bash dnf info redis ``` Package names differ between the two families. For example, the Apache web server is `apache2` on Ubuntu and `httpd` on Rocky Linux, and the Redis server is `redis-server` versus `redis`. Searching first saves guesswork. When you know the file or command you need but not the package, ask which package provides it. DNF can search all repositories directly: ```bash dnf provides '*/bin/dig' ``` ```output bind-utils-32:9.16.23-24.el9.x86_64 : Utilities for querying DNS name servers Repo : appstream ``` On Ubuntu, install `apt-file` once and then search: ```bash sudo apt install apt-file sudo apt-file update apt-file search bin/dig ``` ## Step 3 - Installing and removing packages Install one or more packages. Both tools show what will be installed, including dependencies, and ask for confirmation: ```bash sudo apt install nginx ``` ```bash sudo dnf install nginx ``` Add `-y` to skip the confirmation in scripts and automation. To install a specific version, first list the versions available, then pin it in the install command: ```bash apt list -a nginx sudo apt install nginx=1.24.0-2ubuntu7 ``` ```bash dnf list --showduplicates nginx sudo dnf install nginx-1.20.1-20.el9 ``` Use the exact version strings shown by the listing commands on your system; the ones above are only examples. To install a package file you downloaded, pass its path. Using `apt` or `dnf` rather than `dpkg -i` or `rpm -i` means missing dependencies are fetched from the repositories: ```bash sudo apt install ./package_name.deb ``` ```bash sudo dnf install ./package_name.rpm ``` Removing packages works differently on each family. On Ubuntu, `remove` keeps configuration files in `/etc`, `purge` deletes them too, and `autoremove` removes dependencies nothing needs any more: ```bash sudo apt remove nginx sudo apt purge nginx sudo apt autoremove ``` On Rocky Linux, `dnf remove` also removes dependencies that were pulled in only for that package. Modified configuration files are kept with an `.rpmsave` extension: ```bash sudo dnf remove nginx ``` ## Step 4 - Listing installed packages and their files List installed packages, or check whether a specific one is installed: ```bash apt list --installed nginx ``` ```bash dnf list --installed nginx ``` List the files a package installed, which is how you find its configuration files and binaries: ```bash dpkg -L nginx ``` ```bash rpm -ql nginx ``` Find which installed package owns a file: ```bash dpkg -S /usr/sbin/nginx ``` ```output nginx: /usr/sbin/nginx ``` ```bash rpm -qf /usr/sbin/nginx ``` ```output nginx-1.20.1-20.el9.x86_64 ``` Show what a package depends on, and which installed packages depend on it: ```bash apt-cache depends nginx apt-cache rdepends --installed nginx ``` ```bash dnf repoquery --requires nginx dnf repoquery --installed --whatrequires nginx ``` ## Step 5 - Holding a package at its current version Sometimes a package must not be upgraded, for example a database server that you want to upgrade manually during a maintenance window. On Ubuntu, mark it as held: ```bash sudo apt-mark hold postgresql-16 apt-mark showhold ``` ```output postgresql-16 ``` Release the hold later with `sudo apt-mark unhold postgresql-16`. On Rocky Linux, use the versionlock plugin: ```bash sudo dnf install python3-dnf-plugin-versionlock sudo dnf versionlock add postgresql-server sudo dnf versionlock list ``` Remove the lock with `sudo dnf versionlock delete postgresql-server`. Held packages do not receive security fixes either, so keep holds short and documented. ## Step 6 - Adding a third-party repository Software that is not in the distribution's repositories, or that you need in a newer version, usually comes from the vendor's own repository. The repository must be signed, and on Ubuntu the key must be tied to that repository only. On Ubuntu 24.04, repositories are defined in `/etc/apt/sources.list.d/`. The steps below add the official Nginx repository as an example. Download the signing key into `/etc/apt/keyrings`: ```bash sudo install -m 0755 -d /etc/apt/keyrings curl -fsSL https://nginx.org/keys/nginx_signing.key | sudo gpg --dearmor -o /etc/apt/keyrings/nginx.gpg ``` Create the repository definition in the deb822 format, with `Signed-By` pointing to that key so it cannot be used to sign packages from other repositories: ```bash sudo nano /etc/apt/sources.list.d/nginx.sources ``` ```text Types: deb URIs: https://nginx.org/packages/ubuntu Suites: noble Components: nginx Signed-By: /etc/apt/keyrings/nginx.gpg ``` Refresh the package lists and check that the new repository now provides the package: ```bash sudo apt update apt-cache policy nginx ``` The `Version table` in the output lists `nginx.org` as a source. Never use the deprecated `apt-key` command: it trusts a key for all repositories at once. On Rocky Linux, repositories are `.repo` files in `/etc/yum.repos.d/`. Many projects ship a release package that installs the file and key for you. The most important one is EPEL, which adds thousands of extra packages; on Rocky Linux 9 it also needs the CRB repository: ```bash sudo dnf install epel-release sudo dnf config-manager --set-enabled crb ``` For a vendor repository, create the file yourself: ```bash sudo nano /etc/yum.repos.d/nginx.repo ``` ```ini [nginx-stable] name=nginx stable repo baseurl=https://nginx.org/packages/centos/$releasever/$basearch/ gpgcheck=1 enabled=1 gpgkey=https://nginx.org/keys/nginx_signing.key module_hotfixes=true ``` Check that it is enabled: ```bash dnf repolist ``` ```output repo id repo name appstream Rocky Linux 9 - AppStream baseos Rocky Linux 9 - BaseOS extras Rocky Linux 9 - Extras nginx-stable nginx stable repo ``` The first time you install a package from it, DNF shows the key fingerprint and asks you to import it. Compare it with the fingerprint published by the vendor before answering `y`. ## Step 7 - Reviewing and undoing changes DNF records every transaction and can undo it, which is one of its main advantages over APT: ```bash sudo dnf history ``` ```output ID | Command line | Date and time | Action(s) | Altered ------------------------------------------------------------------------------ 12 | install nginx | 2026-09-25 09:40 | Install | 4 11 | upgrade | 2026-09-24 07:02 | Upgrade | 31 ``` Show the details of one transaction and undo it: ```bash sudo dnf history info 12 sudo dnf history undo 12 ``` Undoing an upgrade only works while the older package versions are still available in the repositories. APT has no rollback command, but it logs every run. Check what changed and when: ```bash less /var/log/apt/history.log ``` To go back on Ubuntu, reinstall the previous version explicitly as shown in Step 3, which is why a disk snapshot before large upgrades is valuable. ## Step 8 - Automating security updates Ubuntu installs and enables `unattended-upgrades` by default, which applies security updates daily. Verify that it is active: ```bash systemctl status unattended-upgrades cat /etc/apt/apt.conf.d/20auto-upgrades ``` ```output APT::Periodic::Update-Package-Lists "1"; APT::Periodic::Unattended-Upgrade "1"; ``` Run a dry run to see what it would do: ```bash sudo unattended-upgrade --dry-run --debug ``` On Rocky Linux, install `dnf-automatic`, set it to apply only security updates, and enable its timer: ```bash sudo dnf install dnf-automatic sudo nano /etc/dnf/automatic.conf ``` In the `[commands]` section, set: ```ini [commands] upgrade_type = security apply_updates = yes ``` Enable the timer and check when it will run next: ```bash sudo systemctl enable --now dnf-automatic.timer systemctl list-timers dnf-automatic.timer ``` To apply only security updates manually, run `sudo dnf upgrade --security`. ## Command equivalents | Task | APT (Ubuntu, Debian) | DNF (Rocky, AlmaLinux) | |---|---|---| | Refresh metadata | `sudo apt update` | `sudo dnf makecache` | | List updates | `apt list --upgradable` | `dnf check-update` | | Upgrade everything | `sudo apt full-upgrade` | `sudo dnf upgrade` | | Install | `sudo apt install pkg` | `sudo dnf install pkg` | | Remove | `sudo apt remove pkg` / `purge pkg` | `sudo dnf remove pkg` | | Remove unused dependencies | `sudo apt autoremove` | `sudo dnf autoremove` | | Search | `apt search term` | `dnf search term` | | Package details | `apt show pkg` | `dnf info pkg` | | Which package owns a file | `dpkg -S /path` | `rpm -qf /path` | | Files in a package | `dpkg -L pkg` | `rpm -ql pkg` | | Hold a version | `sudo apt-mark hold pkg` | `sudo dnf versionlock add pkg` | | Transaction history | `/var/log/apt/history.log` | `dnf history` | | Clean the cache | `sudo apt clean` | `sudo dnf clean all` | ## Troubleshooting **`Could not get lock /var/lib/dpkg/lock-frontend`.** Another APT process is running, very often `unattended-upgrades` shortly after boot. Wait for it to finish and check what holds the lock with `ps aux | grep -E 'apt|dpkg'`. Do not delete the lock files: interrupting dpkg mid-install is how packages end up broken. **`dpkg was interrupted, you must manually run 'sudo dpkg --configure -a'`.** A previous installation was cut off. Finish configuring the pending packages and let APT repair dependencies: ```bash sudo dpkg --configure -a sudo apt --fix-broken install ``` **`The following packages have unmet dependencies`.** Usually caused by a third-party repository or a manually installed `.deb` built for another release. Run `sudo apt --fix-broken install`, then check with `apt-cache policy package_name` which repository each version comes from. **`NO_PUBKEY` or `The repository is not signed` on `apt update`.** The key in the `Signed-By` path is missing, wrong or expired. Download the current key from the vendor again as shown in Step 6. **DNF metadata or checksum errors.** Clear the cached metadata and download it again: ```bash sudo dnf clean all sudo dnf makecache ``` **DNF reports conflicting packages.** Read the conflict message: it names the two packages and usually the repositories they come from. Remove or disable the repository that provides the incompatible version, or retry with `--allowerasing` after checking which packages DNF proposes to remove. Never force-install with `rpm --nodeps`. ## Conclusion You now know how to perform the everyday package tasks on both major Linux families: keeping the system updated, finding and installing software, pinning versions, adding signed third-party repositories, rolling back changes and fixing the most common errors. As next steps, make sure automatic security updates are active on every server, snapshot servers before large upgrades, and read the guide on upgrading Ubuntu LTS to a new version when your release approaches end of life.