Versions and what you need
The commands were checked against the documentation for these releases. Where they behave differently, the section says so.
- APT: Debian 13 "trixie" (APT 3.0), Ubuntu 24.04 LTS (APT 2.7) and Ubuntu 26.04 LTS (APT 3.1). Linux Mint, Pop!_OS and Raspberry Pi OS use the same tool.
- DNF: Fedora 41 and later, which ship DNF5 as
dnf, and RHEL 9 and 10 with rebuilds such as Rocky Linux and AlmaLinux, which still use DNF 4. - Pacman: Arch Linux and derivatives such as EndeavourOS. Arch is a rolling release, so there is no version to pin.
You need a shell on the machine and an account that can use sudo. If you want to practise the remove and hold commands, a throwaway VM or a snapshot is a better place than a server you depend on. To confirm what you're running:
cat /etc/os-release
apt --version # Debian, Ubuntu and derivatives
dnf --version # Fedora, RHEL and rebuilds
pacman --version # Arch and derivatives
Commands that only read information (search, show, info, list, -Q) work without sudo. Anything that changes the system needs it.
What happens during an install
Your distribution publishes repositories: collections of packages plus an index that lists every package, its version and its dependencies. The package manager keeps a local copy of those indexes, and an install goes roughly like this:
- It looks the name up in the local index, which is why a stale index causes "package not found" errors.
- It works out the dependencies, and their dependencies, and asks you to confirm the full list.
- It downloads the files and checks them. APT verifies the signature on each repository's
InReleaseorReleasefile and then checks every download against the hashes listed there (apt-secure(8)). DNF and Pacman also check a signature on each individual package. - It unpacks the files (programs into
/usr/bin, libraries into/usr/lib, default configuration into/etc) and runs the package's install scripts, which may create a system user or register a service.
Because the package manager tracks every file it installed, it can upgrade or remove the software later. Software installed by hand-copying binaries or running random install scripts doesn't get that.
APT on Debian and Ubuntu
Refresh the index, then upgrade
sudo apt update
apt list --upgradable
sudo apt upgrade
apt update only downloads the indexes. It finishes with either All packages are up to date. or a count of upgradable packages, and any repository that failed shows up as an Err: or W: line, which is worth reading before you go further.
According to apt(8), apt upgrade may install new packages to satisfy dependencies but never removes an installed package; an upgrade that would need a removal is skipped. sudo apt full-upgrade is allowed to remove packages, so read its list before you answer Y. Raspberry Pi OS recommends full-upgrade for routine updates because its packages change dependencies more often than Debian's.
Check it worked: run apt list --upgradable again. Anything still listed was kept back; the kept-back section explains why. On Ubuntu, if the file /var/run/reboot-required exists, an update (usually the kernel) needs a reboot to take effect.
Install, remove and purge
# Install one or more packages
sudo apt install htop tree
# Remove the program but keep its configuration files
sudo apt remove htop
# Remove the program and its system-wide configuration files
sudo apt purge htop
# Remove dependencies nothing needs any more
sudo apt autoremove
Check it worked: dpkg -s tree | grep Status prints Status: install ok installed for an installed package. After a remove (but before a purge), dpkg -l htop shows the state rc: removed, configuration still present.
Read the list autoremove prints. It offers every package that was installed automatically as a dependency and that no manually installed package still needs, which can include something you've come to rely on. sudo apt-mark manual PACKAGE takes a package off that list. Neither remove nor purge touches files in users' home directories.
For searching, apt search TERM matches names and descriptions and apt show PACKAGE prints the version, size, dependencies and which repository it comes from. On Ubuntu 26.04, apt show and apt list open in a pager; press q to leave it.
On scripts: apt(8) says its own output and behaviour may change between versions for the sake of interactive use, and recommends apt-get and apt-cache for scripts because they keep backward compatibility. Typing apt by hand is fine.
Repositories and signing keys
APT reads its sources from /etc/apt/sources.list.d/. The older one-line format lives in /etc/apt/sources.list and *.list files; the newer deb822 format uses *.sources files with one field per line. Ubuntu 24.04 already ships its own entries as /etc/apt/sources.list.d/ubuntu.sources, and the Debian 13 release notes recommend a single debian.sources file in that format. Their example for the main archive and security updates looks like this:
Types: deb
URIs: https://deb.debian.org/debian
Suites: trixie trixie-updates
Components: main non-free-firmware
Signed-By: /usr/share/keyrings/debian-archive-keyring.gpg
Types: deb
URIs: https://security.debian.org/debian-security
Suites: trixie-security
Components: main non-free-firmware
Signed-By: /usr/share/keyrings/debian-archive-keyring.gpg
Since trixie, the .gpg keyring paths are compatibility symlinks to new .pgp files, and the release notes suggest switching Signed-By to the .pgp name. If APT prints Notice: Some sources can be modernized, sudo apt modernize-sources (APT 3.0 and later) converts existing one-line entries to .sources files. Read the new files before you delete anything it leaves behind.
For a third-party repository, keep the vendor's key in its own file, usually under /etc/apt/keyrings/, and reference it with Signed-By in that repository's entry only. A key trusted that way can't vouch for packages from any other repository. The deprecated apt-key command, which added keys globally, is gone entirely in APT 3.1 on Ubuntu 26.04. The Docker Installation Guide walks through a complete third-party example with Docker's own key and repository.
Check it worked: after editing sources, sudo apt update should list a Hit: or Get: line for each repository and no errors. apt policy with no arguments lists every configured source and its priority, and apt policy PACKAGE shows which repository a package's candidate version comes from.
Every repository you add can ship packages whose install scripts run as root, and a repository that stops publishing for your release will break the next release upgrade. Check whether the distribution already packages what you need before adding one.
Kept-back packages
When apt upgrade says The following packages have been kept back, there are two common causes:
- Phased updates (Ubuntu only). Ubuntu releases some updates to a growing share of machines over several days. Ubuntu's phased updates documentation says you can ignore the message; the update installs automatically once your machine is included, and security updates are never phased.
apt policy PACKAGEshows the phasing as, for example,(phased 20%)next to the candidate version. - Changed dependencies. The new version needs a package removed or replaced, which
upgradewon't do.sudo apt full-upgradewill, but read what it proposes to remove first.
Running full-upgrade or apt install PACKAGE just to get rid of a phasing message skips the protection phasing gives you, and Ubuntu doesn't recommend it.
Holds, local .deb files and history
# Keep a package at its current version, list holds, release a hold
sudo apt-mark hold nginx
apt-mark showhold
sudo apt-mark unhold nginx
# Install a downloaded .deb and pull in its dependencies (the ./ matters)
sudo apt install ./package-file.deb
# Which installed package owns this file?
dpkg -S /usr/bin/htop
# Packages no longer available from any configured repository
apt list '?obsolete'
Without the ./, APT treats the argument as a package name to look up in the repositories. To find which package would provide a file you don't have yet, install apt-file, run sudo apt-file update, then apt-file search bin/dig.
APT logs every transaction in /var/log/apt/history.log on all versions. Ubuntu 25.10 and 26.04 (APT 3.1) add apt history-list, apt history-info ID and sudo apt history-undo ID, as described in the Ubuntu 26.04 release notes.
DNF on Fedora and RHEL
Fedora 41 replaced the Python-based DNF 4 with DNF5. Everyday commands are the same on both, but a few subcommands and plugin options changed, and RHEL 9 and 10 still use DNF 4. If a step below differs, check dnf --version first.
# List available updates without changing anything
dnf check-update
# Apply all updates
sudo dnf upgrade
# Install and remove
sudo dnf install htop
sudo dnf remove htop
sudo dnf autoremove
# Search, inspect, and find which package provides a file
dnf search "web server"
dnf info nginx
dnf provides /usr/bin/dig
# Review and undo past transactions
dnf history list
sudo dnf history undo 12
DNF refreshes repository metadata on its own when the cached copy expires, so there's no required "update the index" step. sudo dnf makecache fetches it explicitly, and adding --refresh to a command forces a fresh copy for that run. dnf check-update exits with status 100 when updates are available and 0 when there are none, which makes it handy in monitoring scripts. The number given to history undo is the transaction ID from history list.
Check it worked: rpm -q htop prints the installed version, or package htop is not installed. After a kernel or core-library update, dnf needs-restarting -r (DNF 4, from dnf-plugins-core) or dnf needs-restarting (DNF5, from dnf5-plugins) reports whether a reboot is recommended.
Where DNF 4 and DNF5 differ in commands you're likely to meet:
- Adding a repository file: DNF 4 uses
sudo dnf config-manager --add-repo URL; DNF5 usessudo dnf config-manager addrepo --from-repofile=URL. On both, config-manager comes from the plugins package (dnf-plugins-coreordnf5-plugins). - Version locks: DNF5 provides a versionlock command that stores locks in
/etc/dnf/versionlock.toml. On DNF 4, installpython3-dnf-plugin-versionlockfirst. The commands are then the same:sudo dnf versionlock add nginx,dnf versionlock list,sudo dnf versionlock delete nginx. - yum: on RHEL and Fedora,
yumis a compatibility name fordnf, so older instructions that use it still work.
Pacman on Arch
Pacman's flags follow a pattern: -S works with the sync repositories, -R removes, -Q queries what is installed, and -F searches file lists.
-Syu.# Refresh the databases and upgrade everything, always together
sudo pacman -Syu
# Upgrade and install in one step
sudo pacman -Syu htop
# Remove a package with the dependencies only it needed, plus its config backups
sudo pacman -Rns htop
# Search the repositories, then inspect installed packages
pacman -Ss "text editor"
pacman -Qi htop
pacman -Ql htop # files the package installed
pacman -Qo /usr/bin/htop # which package owns this file
# Find the package that provides a file you don't have (sync the file database first)
sudo pacman -Fy
pacman -F dig
Never run pacman -Sy PACKAGE. Refreshing the databases without upgrading and then installing one package can pull in a build linked against newer libraries than the rest of your system has. The Arch wiki's system maintenance page calls this a partial upgrade and says it's unsupported. The same page recommends reading the Arch news before upgrading, because some upgrades need a manual step.
Check it worked: pacman -Q htop prints the name and installed version, or error: package 'htop' was not found.
A few Arch-specific habits:
- Orphans:
pacman -Qdtqlists packages installed as dependencies that nothing needs now. Review the list, then remove them withpacman -Qdtq | sudo pacman -Rns -. - Package cache: pacman keeps every downloaded package in
/var/cache/pacman/pkg/.paccache -rfrom thepacman-contribpackage keeps the three most recent versions of each and deletes the rest;sudo pacman -Scremoves cached packages that aren't installed. - .pacnew files: when you've edited a configuration file and the new package ships a changed default, pacman saves the new one as
FILE.pacnewinstead of overwriting yours.pacdiff, also frompacman-contrib, finds them and helps you merge. - Holding a package: add it to
IgnorePkgin/etc/pacman.conf. Keep that short-lived, since an ignored package that falls behind its dependencies is another form of partial upgrade.
Same task, three syntaxes
| Task | APT | DNF | Pacman |
|---|---|---|---|
| Refresh package metadata | sudo apt update |
sudo dnf makecache (also automatic) |
Only as part of sudo pacman -Syu |
| List pending updates | apt list --upgradable |
dnf check-update |
checkupdates (pacman-contrib) |
| Upgrade everything | sudo apt upgrade |
sudo dnf upgrade |
sudo pacman -Syu |
| Install | sudo apt install PKG |
sudo dnf install PKG |
sudo pacman -S PKG |
| Remove | sudo apt remove PKG |
sudo dnf remove PKG |
sudo pacman -Rs PKG |
| Remove unneeded dependencies | sudo apt autoremove |
sudo dnf autoremove |
pacman -Qdtq | sudo pacman -Rns - |
| Search | apt search TERM |
dnf search TERM |
pacman -Ss TERM |
| Package details | apt show PKG |
dnf info PKG |
pacman -Si PKG |
| Which package owns a file | dpkg -S PATH |
rpm -qf PATH |
pacman -Qo PATH |
| Install a local file | sudo apt install ./FILE.deb |
sudo dnf install ./FILE.rpm |
sudo pacman -U FILE.pkg.tar.zst |
| Hold a version | sudo apt-mark hold PKG |
sudo dnf versionlock add PKG |
IgnorePkg in /etc/pacman.conf |
| Clear the download cache | sudo apt clean |
sudo dnf clean all |
paccache -r or sudo pacman -Sc |
Error messages and what they mean
"E: Unable to locate package"
APT has no record of that name. Run sudo apt update first, especially on a fresh or long-idle machine, then check the spelling with apt search. On Ubuntu, many packages live in the universe component; sudo add-apt-repository universe enables it if it was turned off. If a download fails with 404 instead, the index is out of date and points at a version the mirror no longer has, and apt update fixes that too.
"Could not get lock /var/lib/dpkg/lock-frontend"
Another APT or dpkg process is running. On a machine that has just booted, it's usually the automatic update job. pgrep -a 'apt|dpkg' shows what holds it. Wait for it to finish. Don't delete the lock files: two package operations writing to the dpkg database at once can leave it inconsistent.
"dpkg was interrupted, you must manually run 'sudo dpkg --configure -a'"
A previous install was cut off, by a lost SSH session or a power cut for example. Run exactly what the message says, sudo dpkg --configure -a, then sudo apt install -f to finish any half-installed dependencies. Running long upgrades inside tmux or screen, as the Debian release notes suggest for remote upgrades, keeps a dropped connection from causing this.
"NO_PUBKEY" or "The following signatures couldn't be verified"
APT can't find the key that signed a repository's index, so it refuses to use that repository. For a third-party repository, download the key again from the vendor's documented URL into the file that the entry's Signed-By line points to. For your distribution's own repositories, reinstalling the keyring package (debian-archive-keyring or ubuntu-keyring) restores it.
DNF: "GPG check FAILED" or a prompt to import a key
The first install from a repository asks you to import its signing key. Accept only if the fingerprint matches the one the repository publishes. A GPG check failure on a package you didn't expect usually means the repository's gpgkey= setting in /etc/yum.repos.d/ points to the wrong key or the key was rotated; fix the key rather than setting gpgcheck=0.
Pacman: "invalid or corrupted package (PGP signature)"
On a system that hasn't been upgraded in a while, the keyring may not know the key a packager now uses. The Arch wiki's package signing page suggests upgrading the keyring first and then the rest of the system: sudo pacman -Sy archlinux-keyring && sudo pacman -Su.
Pacman: "failed to commit transaction (conflicting files)"
A file the new package wants to install already exists and isn't owned by the package being upgraded. pacman -Qo PATH tells you whether another package owns it. A file owned by nothing was usually copied there by hand or by a non-packaged installer. Find out where it came from before you reach for --overwrite.
Flatpak, Snap and AppImage
These formats sit alongside your distribution's package manager rather than replacing it. They bundle an application with most of its libraries, so the same build runs on many distributions and can be newer than what the distribution ships.
- Flatpak is aimed at desktop applications, runs them in a sandbox, and most apps come from the Flathub repository.
- Snap is developed by Canonical and preinstalled on Ubuntu. On Ubuntu, some apt packages (Firefox, for example) are transitional packages that install the snap.
- AppImage is a single file that runs without installation: download it,
chmod +xit, run it. Nothing updates it for you.
For servers and system components (web servers, databases, SSH, the kernel), stick with the distribution's own packages so security updates arrive through the normal update process.
Cleaning up after practice
If you installed htop and tree or added holds just to try the commands, remove them so they don't surprise you later:
# Debian / Ubuntu
sudo apt purge htop tree
sudo apt autoremove
sudo apt-mark unhold nginx # only if you added the hold
sudo apt clean
# Fedora / RHEL
sudo dnf remove htop
sudo dnf versionlock delete nginx # only if you added the lock
sudo dnf clean all
# Arch
sudo pacman -Rns htop
paccache -r
Also remove any test repository files you added under /etc/apt/sources.list.d/ or /etc/yum.repos.d/, along with their keys, and any IgnorePkg entries you added to /etc/pacman.conf. Then run a normal update to confirm everything still resolves cleanly.
Where to go next
- Docker Installation Guide: adding a third-party APT or DNF repository with its signing key, from start to finish.
- Nginx Web Server Setup: a server package installed from the distribution, with its service unit and default configuration.
- Running Your Scripts as Real Services with Systemd: what to do with the services packages install.
- Understanding Linux Permissions: ownership and modes of the files packages put in
/etcand/var.



