How to remove old kernels and free /boot for Ubuntu
/boot full fit make apt show errors like "No space left on device". See kernels you fit remove safely, keep the running one, and make apt work again.
Why apt dey stop to work when /boot full with old kernels
For Ubuntu, every kernel update dey write new set of files inside /boot and leave the previous ones there. So small /boot partition fit full, and apt no fit finish installation again. The repair get two steps. Find out which packages for the machine be kernels and which one you booted with, then remove the rest with apt autoremove --purge.
The order matter. The running kernel na the package wey you must not remove. The machine fit already dey in a state where apt no fit run at all. Diagnose first.
Wetin the failure actually look like
A kernel version dey install two big files inside /boot: the compressed kernel (vmlinuz-<version>) and the initramfs (initial RAM filesystem, initrd.img-<version>, the small archive wey kernel dey unpack before e mount the real root). The initramfs dey build for your machine when installation dey happen. Na why the installation need free space, no be only download bandwidth. If space finish, the build fail and e carry the package down with am.
update-initramfs: Generating /boot/initrd.img-6.8.0-64-generic
gzip: stdout: No space left on device
E: mkinitramfs failure gzip 1
update-initramfs: failed for /boot/initrd.img-6.8.0-64-generic with 1.
dpkg: error processing package linux-image-6.8.0-64-generic (--configure):
installed linux-image-6.8.0-64-generic package post-installation script subprocess returned error exit status 1The version string go be your own. The compressor name dey come from COMPRESS= inside /etc/initramfs-tools/initramfs.conf, so recent image fit name zstd while older one name gzip. The two lines wey identify this problem na No space left on device and the dpkg: error processing package line under am.
After that, the package remain half-configured. Every later apt run go try configure am again, fail the same way, and end with E: Sub-process /usr/bin/dpkg returned an error code (1). Na this part matter beyond disk space: unattended-upgrades dey run for its timer, hit the same error, and stop. The server go look healthy but e go quietly stop applying security patches. E also mean say any unrelated installation wey you try go fail with that same line, and blame go land on anything wey you dey add at that time. Na why a Tailscale installation wey fail for Ubuntu worth reading first as an apt error. If apt update fail before you reach this point, na separate problem, often duplicate entry after the deb822 sources migration.
Check whether /boot na separate partition
Before you delete anything, find out wetin you really dey free.
findmnt /boot
findmnt -T /boot
df -h /boot /The first command go print line only if /boot dey as e own mount point. The second one go always print, and e go show the filesystem wey really hold /boot. If both of dem show the same filesystem as /, then /boot na only directory for the root filesystem and e no fit full by itself: na your root filesystem full, and old kernels na only one of the things wey contribute. For this case, sudo apt clean, wey dey empty the downloaded .deb files under /var/cache/apt/archives, go create space for you. For machine wey get real /boot partition, apt clean no go free any space there at all, because the cache dey for another filesystem.
Now get the number wey you go use compare.
df -h /boot
ls -lh /boot/vmlinuz-$(uname -r) /boot/initrd.img-$(uname -r)Compare the Avail column with the size of those two files. The initrd na the bigger one. The next kernel update need space for another pair wey roughly get that size, so if Avail smaller than the current initrd, the next update go fail already.
Find di kernel wey you dey run
uname -r
cat /var/run/reboot-required.pkgsuname -r dey print release string of di kernel wey dey memory now. Copy that string put somewhere. Na that version you no suppose touch.
Di second file dey exist only when package request reboot. linux-image line inside am mean say newer kernel don install for disk but e never use, because machine never reboot since e land. Reboot before you clean if you fit. apt dey protect di kernel wey dey run and di newest one, so if you clean while old kernel dey run, e go pin one extra version wey you no need.
List kernel packages and read their states
dpkg --list | grep -E 'linux-(image|modules|headers|tools)' | awk '{print $1, $2}'The first field na dpkg state code. ii mean say package install and configure finish. iF mean say package install but configuration never finish. Na exactly this one the failed upgrade above leave behind. rc mean say package remove but e still keep the configuration for disk. E no dey use space for /boot and e safe to purge.
The second field tell you the kind package wey e be. Name wey get version inside am, like linux-image-6.8.0-64-generic, na one specific kernel. Name wey no get version, like linux-image-generic, linux-headers-generic or linux-generic, na meta package. E no contain kernel. The only work wey e get na to depend on the newest versioned kernel, so apt upgrade go pull new kernels enter. If you remove meta package, machine no go receive kernel updates again, and nothing go warn you afterwards.
The families divide like this. linux-image-* hold the compressed kernel for /boot. linux-modules-* and linux-modules-extra-* hold drivers under /lib/modules. linux-headers-* hold build headers under /usr/src. This mean say purging headers go free space for root filesystem, not for /boot. If your problem na /boot partition wey full, na image packages you need find.
ls -1 /boot/vmlinuz-*
ls -1 /lib/modules/These two listings suppose match each other and also match the dpkg --list output. Directory for /lib/modules wey no get matching installed package na leftover from person wey delete files by hand.
How apt dey decide which kernels to keep
apt autoremove no go remove kernel wey e consider protected, and the protected set include the kernel wey you dey run now. The retention policy don change between Ubuntu releases, so read am from your own machine instead of trusting any number wey person write down anywhere.
apt-config dump | grep -i -e neverautoremove -e versionedkernel
ls -l /etc/apt/apt.conf.d/01autoremove /etc/apt/apt.conf.d/01autoremove-kernelsAPT::NeverAutoRemove na the list of package name patterns wey apt autoremove no dey touch. APT::VersionedKernelPackages na the list of name prefixes wey apt first dey treat as versioned kernel packages. For releases wey generate /etc/apt/apt.conf.d/01autoremove-kernels, /etc/kernel/postinst.d/apt-auto-removal dey rewrite that file every time dem install kernel package, so editing am by hand no get use: the next kernel install go overwrite your edit. For releases wey no get the file, apt dey apply the same protection internally. Either way, apt-config dump go show the rules wey dey active for your box, and na that output be the correct answer for your release.
Cleanup wey safe to run
sudo apt update
sudo apt autoremove --purge --dry-run--dry-run no dey change anything for disk, and e dey print exactly wetin real run for remove. Read the list. Two things suppose make you stop. Meta package like linux-generic or linux-image-generic for the removal list mean say something mark am as automatic, and removing am go stop your kernel updates. The string from uname -r for the removal list mean say the kernel wey dey run no get protection. This no suppose happen, so investigate am before you continue.
If the list look correct, run am for real.
sudo apt autoremove --purge
df -h /bootThe --purge half dey delete the leftover configuration together with the package. E free small extra space, and e keep dpkg --list free from plenty rc lines, so the next audit go dey easy to read.
Then confirm say the boot menu rebuild. Removing a kernel package dey run update-grub for you, so the menu suppose reference only files wey still dey exist.
sudo grep -o 'vmlinuz-[^ ]*' /boot/grub/grub.cfg | sort -u
ls -1 /boot/vmlinuz-*Every version for the first output must appear for the second one. A menu entry wey point to file wey don disappear na how working server fit become one wey stop for GRUB prompt. Na one way to get VPS wey no go boot after kernel update, and e much harder to fix am from rescue console than to prevent am here.
Why apt autoremove sometimes no remove anything
apt autoremove only removes packages wey dem mark as automatic. E mean say dem install am as dependency for another thing. Kernel wey you install by yourself with apt install linux-image-6.8.0-40-generic, dem mark as manual. Autoremove no go ever touch am, no matter how old e be.
apt-mark showmanual | grep -E '^linux-'Any versioned kernel for that output no dey visible to autoremove. Mark am as automatic again, using version strings from your own listing:
sudo apt-mark auto linux-image-6.8.0-40-generic linux-modules-6.8.0-40-generic
sudo apt autoremove --purge --dry-runLeave the meta packages marked manual. Dem suppose dey manual because na you ask for dem.
Remove one named kernel on purpose
Sometimes you go want make one particular version comot now, instead of waiting for when policy allow am. Name the image package, then make apt work out the rest.
sudo apt purge linux-image-6.8.0-40-genericapt dey print removal list before e do anything, because linux-modules-extra-* depend on the image package and must comot for the same transaction. That list wey e print na your real safety check. Na there you go catch when meta package dey comot together with the version wey you mean remove. Answer n if you see anything wey you no expect. After that, run sudo apt autoremove --purge to collect the module and header packages wey no get reason to remain again.
Why you no dey remove the kernel wey dey run
The kernel wey already dey for memory go continue to run after dem delete the files, so nothing go look broken at first. Wetin go break na everything wey the kernel never load yet. Purging linux-modules-$(uname -r) go delete /lib/modules/$(uname -r)/, so the next module load go fail:
modprobe: FATAL: Module nf_tables not found in directory /lib/modules/6.8.0-64-genericFirewall reload go fail from that point, and mounting filesystem type wey this kernel never touch since boot go fail too. Meanwhile, /boot/vmlinuz-$(uname -r) don disappear, so the boot menu no longer offer the kernel wey you dey run, and the next reboot go land somewhere else. The machine go continue to serve network traffic, but e don already become unbootable. Check uname -r against the removal list every time.
When /boot full reach where apt no fit run again
Na this situation dey make people search for this page. apt autoremove need dpkg to finish configuring the kernel package wey only configure halfway first. That step rebuild initramfs, but e need space inside /boot wey no get space. Break the loop by hand, just this once.
uname -r
ls -1 /boot/initrd.img-*Choose one initrd file wey version no be the string uname -r give you, then delete only that file.
sudo rm /boot/initrd.img-6.8.0-40-generic
sudo apt --fix-broken install
sudo apt autoremove --purge
sudo update-grubEvery line get reason. rm na deliberate exception wey make dpkg believe say file dey, even though e no dey. apt --fix-broken install finish the configuration wey fail before, now say space don dey for initramfs. autoremove --purge then remove the package wey file you delete belong to, together with the other old versions. This make dpkg match wetin really dey for disk again. update-grub rebuild the menu from the files wey actually dey. No reboot between rm and update-grub, because during that time the menu fit still point to the file wey you just delete. If dpkg complain say e interrupt, sudo dpkg --configure -a do the same repair as apt --fix-broken install.
The same job for dnf systems
If your VPS dey run Fedora or one of the RHEL rebuilds like Rocky Linux, the method dey different. Debian and Ubuntu protect kernels with apt autoremove rules. Dem leave the cleanup for you or for unattended-upgrades to trigger. But dnf enforce a count wey dem call installonly_limit, and e automatically remove the oldest kernel once a new install go pass that number. Read the value wey dey active with grep installonly_limit /etc/dnf/dnf.conf and man 5 dnf.conf. Use sudo dnf remove --oldinstallonly to clear any existing backlog. The running kernel dey protected there too. For the wider comparison between both package managers, see the dnf and apt command equivalents.
Make sure e no happen again
Cleanup wey depend on say you go remember am go fail one day, so put am for the thing wey dey install the kernels. Open /etc/apt/apt.conf.d/50unattended-upgrades and find these keys. The shipped file don already get dem as commented lines:
Unattended-Upgrade::Remove-Unused-Kernel-Packages "true";
Unattended-Upgrade::Remove-Unused-Dependencies "true";Remove the comment from dem instead of adding another copy for the end. For apt configuration, the last assignment for a key na the one wey win. So duplicate fit make the file disagree with itself and hide which value really dey active. Check wetin the parser finally use, and monitor one run wey no change anything:
apt-config dump | grep -i 'Unattended-Upgrade::Remove'
sudo unattended-upgrade --dry-run --debug
sudo tail -n 40 /var/log/unattended-upgrades/unattended-upgrades.logThe log na the proof. E record every run, so upgrade wey fail because space no dey enough go show for there long before anybody notice say the machine no dey receive patches. The rest of that configuration dey covered for automatic security updates for Ubuntu.
Before the next kernel land, get one number to check. Na the same pair of commands from the beginning of this guide:
df -h /boot
ls -lh /boot/initrd.img-$(uname -r)If Avail no big pass that file by a comfortable margin, the next kernel go fail exactly as we describe above. So fix am now instead of waiting until upgrade time. This check worth one minute together with your other disk health checks for a VPS. E matter pass just before a release upgrade, because moving Ubuntu 24.04 to 26.04 installs a fresh kernel early for the process, and do-release-upgrade go refuse to continue when /boot no get enough space.
FAQ
Why Ubuntu dey keep old kernels instead of deleting dem?
Because if one kernel no boot, you no go get another one to select. If you keep the previous version, you fit recover from bad update through GRUB menu instead of using provider rescue console. apt therefore dey protect some kernel packages from automatic removal, and e always include the one wey you dey run. Run apt-config dump | grep -i neverautoremove to see the exact patterns wey your release dey protect, because the policy don change between releases.
apt autoremove --purge safe to run for production server?
Yes, as long as you read the dry run first. Run sudo apt autoremove --purge --dry-run, wey no dey write anything, and check the list wey e print. Stop if e contain meta package like linux-generic or linux-image-generic, because removing one of dem go stop future kernel updates. Stop too if e contain the version string wey uname -r print. If none of dem appear, the removals na old kernels and orphaned dependencies.
apt autoremove remove nothing and /boot still full. Wetin I go do now?
The old kernels almost certainly dey marked manual, and autoremove only dey touch packages wey dem mark automatic. Run apt-mark showmanual | grep -E '^linux-'. Any versioned kernel wey dey listed there, person install am by hand at some point. Mark am automatic with sudo apt-mark auto linux-image-<version> and run the dry run again, or purge that one version directly with sudo apt purge linux-image-<version>.
I fit delete files from /boot by hand?
Only as deliberate one-off, when /boot full reach point where apt no fit configure the broken kernel package. Delete one initrd.img-<version> file wey version no be the output of uname -r, then immediately run sudo apt --fix-broken install, sudo apt autoremove --purge and sudo update-grub. If you delete files without those follow-up steps, dpkg go record packages wey their files don disappear, and GRUB menu entries go still point to missing files. The machine go fail for the next reboot instead of failing immediately when you make the mistake.