KB
Linux Administration

Package Management and System Patching

7 min read1463 words18 code blocks

At a glance#

  • Purpose: Install and manage packages, and apply security patches to Linux servers in a controlled way.
  • Applies to: RHEL/Rocky/AlmaLinux (dnf/yum) and Ubuntu/Debian (apt).
  • Risk: Medium to High — updates can restart services, change behaviour, or require a reboot.
  • Time: 30–60 minutes per server.

Overview#

Patching is the highest-value security work there is — most breaches exploit vulnerabilities that already had a fix available. It is also the change most likely to break a working system, which is why it needs a procedure rather than a habit.

Our estate patches reactively: updates are applied when a VAPT finding or vendor advisory identifies a vulnerability that affects us, not on a fixed monthly cadence. That makes it especially important to be able to answer, quickly, "is this server affected and what will fixing it change?"

Package manager quick reference#

TaskRHEL familyDebian family
Refresh metadatasudo dnf makecachesudo apt update
List upgradablesudo dnf check-updateapt list --upgradable
Upgrade everythingsudo dnf updatesudo apt upgrade
Security onlysudo dnf update --securitysudo unattended-upgrade --dry-run
Installsudo dnf install pkgsudo apt install pkg
Removesudo dnf remove pkgsudo apt remove pkg
Searchdnf search termapt search term
Package infodnf info pkgapt show pkg
Which package owns a filerpm -qf /path/filedpkg -S /path/file
Files in a packagerpm -ql pkgdpkg -L pkg
Installed listrpm -qadpkg -l
Historydnf history/var/log/apt/history.log

Before you patch#

1. Know what you are changing#

bash
# RHEL - what would be updated, and why
sudo dnf check-update
sudo dnf updateinfo list security
sudo dnf updateinfo info CVE-2026-12345

# Debian - what would be updated
sudo apt update
apt list --upgradable
apt-get -s upgrade | grep -E "^Inst"
Note: apt-get -s upgrade simulates without changing anything. It is the safest way to see exactly what a patch run will do before committing to it.

2. Check whether a specific CVE applies#

bash
# RHEL
sudo dnf updateinfo list --cve CVE-2026-12345

# Debian - check the installed version against the advisory
apt-cache policy openssl

3. Take a snapshot#

For a VM, take a snapshot before any patch run. It is the fastest rollback there is.

powershell
New-Snapshot -VM 'web01' -Name 'CHG-1105 - pre-patch - anup' `
  -Description 'Before security patch run. Remove after 72h.'

See VMware Snapshot Management.

4. Record current state#

bash
uname -r
rpm -qa | sort > /root/pkgs-before-$(date +%F).txt      # RHEL
dpkg -l  > /root/pkgs-before-$(date +%F).txt            # Debian
systemctl list-units --type=service --state=running > /root/services-before-$(date +%F).txt

Applying patches#

Security-only updates#

Preferred for a reactive patch run — smallest change, least risk.

bash
# RHEL
sudo dnf update --security

# with a specific severity floor
sudo dnf update --security --sec-severity=Important

# a single CVE
sudo dnf update --cve CVE-2026-12345

Debian does not separate security updates as cleanly. Restrict to the security repository:

bash
sudo apt update
sudo apt install -s $(apt list --upgradable 2>/dev/null | grep -i security | cut -d/ -f1)

Or configure unattended-upgrades to handle security only, and run it manually:

bash
sudo unattended-upgrade --dry-run -d
sudo unattended-upgrade -d

Single package#

bash
sudo dnf update openssl
sudo apt install --only-upgrade openssl

Full update#

bash
sudo dnf update
sudo apt update && sudo apt upgrade
Warning: apt upgrade never removes packages. apt full-upgrade (formerly dist-upgrade) will remove packages to resolve dependencies. Read its output carefully before confirming — on a production server, a removal is rarely what you want.

Holding a package back#

When a package must not change — a database engine on a certified version, a kernel with a driver dependency:

bash
# RHEL
sudo dnf install python3-dnf-plugin-versionlock
sudo dnf versionlock add mysql-server
sudo dnf versionlock list

# Debian
sudo apt-mark hold mysql-server
apt-mark showhold
sudo apt-mark unhold mysql-server

Reboot decisions#

A patch is not applied until the affected process restarts. Kernel, glibc and systemd updates require a reboot.

bash
# RHEL - is a reboot needed, and what needs restarting
sudo dnf install -y yum-utils
sudo needs-restarting -r ; echo "exit=$?"     # exit 1 = reboot required
sudo needs-restarting -s                      # services using outdated libraries

# Debian
[ -f /var/run/reboot-required ] && cat /var/run/reboot-required
sudo apt install -y needrestart
sudo needrestart -r l

If a reboot is not possible immediately, restart the specific services still using the old library:

bash
sudo needs-restarting -s | while read svc; do
  echo "Restarting $svc"
  sudo systemctl restart "$svc"
done
Warning: A patched library on disk does nothing while processes still hold the old version mapped in memory. A server that shows the fixed package version but has not restarted the service is still vulnerable, and will still fail a re-scan.

Verification#

bash
# package version now installed
rpm -q openssl                  # RHEL
dpkg -l openssl                 # Debian

# nothing outstanding
sudo dnf check-update ; echo "exit=$?"        # exit 100 = updates available
apt list --upgradable

# kernel running matches the newest installed
uname -r
rpm -qa kernel | sort -V | tail -1

# services all came back
systemctl --failed
diff /root/services-before-$(date +%F).txt <(systemctl list-units --type=service --state=running)

# nothing needs restarting
sudo needs-restarting -r

Then test the actual application — load the site, connect to the database, send a test mail. A clean package list is not a working service.

Only after that, remove the VM snapshot.

Rollback#

RHEL — transaction history#

dnf records every transaction and can reverse one:

bash
sudo dnf history
sudo dnf history info 42
sudo dnf history undo 42

Debian — reinstall the previous version#

bash
# what versions are available
apt-cache policy openssl

# install a specific one
sudo apt install openssl=1.1.1f-1ubuntu2.16

Kernel — boot the previous one#

bash
sudo grubby --info=ALL | grep -E "^kernel|^index"
sudo grubby --set-default-index=1
sudo reboot

Or select the older kernel at the GRUB menu during boot.

VM snapshot#

The most reliable rollback for a patch run that broke something non-obvious. Revert and investigate offline.

Repository management#

bash
# RHEL
sudo dnf repolist
sudo dnf repolist --all
sudo dnf config-manager --set-disabled repoid
sudo dnf config-manager --set-enabled repoid

# Debian
grep -r . /etc/apt/sources.list /etc/apt/sources.list.d/
sudo apt-key list        # deprecated; modern keys live in /etc/apt/keyrings/

For servers with no internet route, build a local repository from installation media — see Creating Local Repo for Red hat Server.

Cleaning up#

bash
# RHEL - remove old kernels and orphaned dependencies
sudo dnf autoremove
sudo dnf clean all
sudo package-cleanup --oldkernels --count=2

# Debian
sudo apt autoremove --purge
sudo apt clean
Note: Keep at least two kernels installed. If the newest one fails to boot, the previous one is your recovery path.

Patch run checklist#

  • [ ] Change reference raised and approved
  • [ ] VM snapshot taken
  • [ ] Package and service state recorded
  • [ ] Reviewed what will change (check-update / -s upgrade)
  • [ ] Patches applied
  • [ ] Reboot performed, or affected services restarted
  • [ ] systemctl --failed is clean
  • [ ] Application tested end to end
  • [ ] Monitoring shows the host healthy
  • [ ] Snapshot removed within 72 hours

Troubleshooting#

SymptomCause and fix
Cannot find a valid baseurl for repoNo route to the repository, or DNS failure. Test with curl. For isolated hosts, build a local repo.
Could not get lock /var/lib/dpkg/lockAnother apt process running, or a stale lock after a crash. Wait, then check with sudo lsof /var/lib/dpkg/lock.
Dependency conflictsThird-party repo conflicting with base. Disable the extra repo, or use --allowerasing after reviewing what it removes.
Package updated but the vulnerability scanner still flags itService not restarted, or reboot pending. Run needs-restarting -s.
Server will not boot after a kernel updateSelect the previous kernel at the GRUB menu, then set it default with grubby.
apt upgrade holds packages backThey need a removal to proceed. Review apt full-upgrade -s before running it.
Disk full during an update/var filled with cached packages. dnf clean all or apt clean.
GPG key errorsRepository key missing or expired. Import the vendor's current key.
Service fails after patchingConfig file replaced or format changed. Check for .rpmnew/.rpmsave or .dpkg-dist files alongside the config.
Note: .rpmnew files are the packaged config the update wanted to install; .rpmsave is your old one that got replaced. Both are silent. Find them after any significant update: ``bash sudo find /etc -name "*.rpmnew" -o -name "*.rpmsave" -o -name "*.dpkg-dist" ``