Package Management and System Patching
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#
| Task | RHEL family | Debian family |
|---|---|---|
| Refresh metadata | sudo dnf makecache | sudo apt update |
| List upgradable | sudo dnf check-update | apt list --upgradable |
| Upgrade everything | sudo dnf update | sudo apt upgrade |
| Security only | sudo dnf update --security | sudo unattended-upgrade --dry-run |
| Install | sudo dnf install pkg | sudo apt install pkg |
| Remove | sudo dnf remove pkg | sudo apt remove pkg |
| Search | dnf search term | apt search term |
| Package info | dnf info pkg | apt show pkg |
| Which package owns a file | rpm -qf /path/file | dpkg -S /path/file |
| Files in a package | rpm -ql pkg | dpkg -L pkg |
| Installed list | rpm -qa | dpkg -l |
| History | dnf history | /var/log/apt/history.log |
Before you patch#
1. Know what you are changing#
# 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#
# RHEL
sudo dnf updateinfo list --cve CVE-2026-12345
# Debian - check the installed version against the advisory
apt-cache policy openssl3. Take a snapshot#
For a VM, take a snapshot before any patch run. It is the fastest rollback there is.
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#
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).txtApplying patches#
Security-only updates#
Preferred for a reactive patch run — smallest change, least risk.
# 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-12345Debian does not separate security updates as cleanly. Restrict to the security repository:
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:
sudo unattended-upgrade --dry-run -d
sudo unattended-upgrade -dSingle package#
sudo dnf update openssl
sudo apt install --only-upgrade opensslFull update#
sudo dnf update
sudo apt update && sudo apt upgradeWarning:apt upgradenever removes packages.apt full-upgrade(formerlydist-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:
# 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-serverReboot decisions#
A patch is not applied until the affected process restarts. Kernel, glibc and systemd updates require a reboot.
# 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 lIf a reboot is not possible immediately, restart the specific services still using the old library:
sudo needs-restarting -s | while read svc; do
echo "Restarting $svc"
sudo systemctl restart "$svc"
doneWarning: 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#
# 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 -rThen 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:
sudo dnf history
sudo dnf history info 42
sudo dnf history undo 42Debian — reinstall the previous version#
# what versions are available
apt-cache policy openssl
# install a specific one
sudo apt install openssl=1.1.1f-1ubuntu2.16Kernel — boot the previous one#
sudo grubby --info=ALL | grep -E "^kernel|^index"
sudo grubby --set-default-index=1
sudo rebootOr 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#
# 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#
# 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 cleanNote: 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 --failedis clean - [ ] Application tested end to end
- [ ] Monitoring shows the host healthy
- [ ] Snapshot removed within 72 hours
Troubleshooting#
| Symptom | Cause and fix |
|---|---|
Cannot find a valid baseurl for repo | No route to the repository, or DNS failure. Test with curl. For isolated hosts, build a local repo. |
Could not get lock /var/lib/dpkg/lock | Another apt process running, or a stale lock after a crash. Wait, then check with sudo lsof /var/lib/dpkg/lock. |
| Dependency conflicts | Third-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 it | Service not restarted, or reboot pending. Run needs-restarting -s. |
| Server will not boot after a kernel update | Select the previous kernel at the GRUB menu, then set it default with grubby. |
apt upgrade holds packages back | They 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 errors | Repository key missing or expired. Import the vendor's current key. |
| Service fails after patching | Config file replaced or format changed. Check for .rpmnew/.rpmsave or .dpkg-dist files alongside the config. |
Note:.rpmnewfiles are the packaged config the update wanted to install;.rpmsaveis 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"``