devops2025-05-20·7·57/348

Cleaning Up Old Kernels on Linux

Guide to safely removing old Linux kernels to free disk space, including manual cleanup, automatic configuration, and recovery procedures.

Cleaning Up Old Kernels on Linux

Linux keeps old kernels as fallback options, but they accumulate and consume significant disk space. My /boot partition was 100% full with 15 old kernels. This guide covers safe kernel cleanup on Ubuntu/Debian systems.

Environment

  • OS: Ubuntu 22.04 LTS
  • Current kernel: 5.15.0-84-generic
  • Problem: /boot partition full
$ uname -r
5.15.0-84-generic

$ df -h /boot
Filesystem      Size  Used Avail Use% Mounted on
/dev/sda1       512M  512M     0 100% /boot

The Problem

$ ls -la /boot/vmlinuz-* | wc -l
15

# Too many kernels consuming all boot space
$ ls -la /boot/vmlinuz-*
-rw-r--r-- 1 root root 11M Jun 25  2024 vmlinuz-5.15.0-25-generic
-rw-r--r-- 1 root root 11M Jul 15  2024 vmlinuz-5.15.0-50-generic
-rw-r--r-- 1 root root 11M Aug 20  2024 vmlinuz-5.15.0-56-generic
-rw-r--r-- 1 root root 11M Sep 30  2024 vmlinuz-5.15.0-67-generic
-rw-r--r-- 1 root root 11M Oct 15  2024 vmlinuz-5.15.0-73-generic
-rw-r--r-- 1 root root 11M Nov 20  2024 vmlinuz-5.15.0-76-generic
-rw-r--r-- 1 root root 11M Dec 10  2024 vmlinuz-5.15.0-78-generic
-rw-r--r-- 1 root root 11M Jan 15  2025 vmlinuz-5.15.0-79-generic
-rw-r--r-- 1 root root 11M Feb 28  2025 vmlinuz-5.15.0-82-generic
-rw-r--r-- 1 root root 11M Mar 20  2025 vmlinuz-5.15.0-83-generic
-rw-r--r-- 1 root root 11M Apr 15  2025 vmlinuz-5.15.0-84-generic

# Cannot install new updates
$ sudo apt update
E: You don't have enough free space in /var/cache/apt/archives/

Analysis

Step 1: Check Installed Kernels

# List installed kernels
$ dpkg -l linux-image-* | grep ^ii
ii  linux-image-5.15.0-25-generic    5.15.0-25.25    amd64    Signed kernel image generic
ii  linux-image-5.15.0-50-generic    5.15.0-50.56    amd64    Signed kernel image generic
ii  linux-image-5.15.0-56-generic    5.15.0-56.62    amd64    Signed kernel image generic
ii  linux-image-5.15.0-76-generic    5.15.0-76.83    amd64    Signed kernel image generic
ii  linux-image-5.15.0-84-generic    5.15.0-84.94    amd64    Signed kernel image generic

# Check current running kernel
$ uname -r
5.15.0-84-generic

Step 2: Calculate Space Usage

# Size of kernel files
$ du -sh /boot/
512M    /boot/

# Size per kernel version
$ for ver in $(ls /boot/vmlinuz-* | sed 's/.*vmlinuz-//'); do
    echo "$ver: $(du -sh /boot/*$ver* 2>/dev/null | awk '{sum += $1} END {print sum}')"
done

Solution

Fix 1: Use apt autoremove (Recommended)

# Automatically remove old kernels
$ sudo apt autoremove --purge

# This removes kernels not currently running and not marked as manual
Reading package lists... Done
The following packages will be REMOVED:
  linux-image-5.15.0-25-generic
  linux-image-5.15.0-50-generic
  linux-image-5.15.0-56-generic
  linux-image-5.15.0-76-generic
  linux-image-5.15.0-78-generic
  linux-image-5.15.0-79-generic
  linux-image-5.15.0-82-generic
  linux-image-5.15.0-83-generic
0 upgraded, 8 newly removed, 0 to upgrade and 0 not to upgrade.

# Verify space freed
$ df -h /boot
Filesystem      Size  Used Avail Use% Mounted on
/dev/sda1       512M  128M  384M  25% /boot

Fix 2: Manually Remove Specific Kernels

# Remove specific kernel version
$ sudo apt purge linux-image-5.15.0-25-generic linux-image-5.15.0-50-generic

# Remove all kernels except current
$ CURRENT=$(uname -r)
$ dpkg -l linux-image-* | grep ^ii | awk '{print $2}' | \
    grep -v "$CURRENT" | xargs sudo apt purge -y

# Update GRUB
$ sudo update-grub

Fix 3: Configure Automatic Cleanup

# Set to keep only 2 kernels
$ echo 'GRUB_DEFAULT="saved"' | sudo tee -a /etc/default/grub
$ echo 'GRUB_SAVEDEFAULT=true' | sudo tee -a /etc/default/grub

# Or use synaptic for GUI management
$ sudo apt install synaptic

Fix 4: Clean Boot Cache

# Remove old initrd images
$ sudo find /boot -name "initrd.img-*" -mtime +30 -delete

# Remove old System.map files
$ sudo find /boot -name "System.map-*" -mtime +30 -delete

# Clean GRUB cache
$ sudo grub-mkconfig -o /boot/grub/grub.cfg

Configure Automatic Kernel Cleanup

# Create script for automated cleanup
$ sudo cat > /usr/local/bin/cleanup-kernels.sh << 'EOF'
#!/bin/bash
KEEP_KERNELS=2
CURRENT=$(uname -r)

# Get list of installed kernels
INSTALLED=$(dpkg -l linux-image-* | grep ^ii | awk '{print $2}' | \
    sed 's/linux-image-//' | sort -V)

# Count kernels
COUNT=$(echo "$INSTALLED" | wc -l)

if [ "$COUNT" -gt "$KEEP_KERNELS" ]; then
    REMOVE_COUNT=$((COUNT - KEEP_KERNELS))
    echo "Removing $REMOVE_COUNT old kernels..."
    
    echo "$INSTALLED" | head -n "$REMOVE_COUNT" | while read kernel; do
        if [ "$kernel" != "$CURRENT" ]; then
            sudo apt purge -y "linux-image-${kernel}"
        fi
    done
    
    sudo update-grub
fi
EOF

$ sudo chmod +x /usr/local/bin/cleanup-kernels.sh

# Add to weekly cron
$ sudo crontab -e
0 3 * * 0 /usr/local/bin/cleanup-kernels.sh >> /var/log/kernel-cleanup.log 2>&1

Verify Cleanup

# Check remaining kernels
$ dpkg -l linux-image-* | grep ^ii
ii  linux-image-5.15.0-83-generic    5.15.0-83.93    amd64    Signed kernel image generic
ii  linux-image-5.15.0-84-generic    5.15.0-84.94    amd64    Signed kernel image generic

# Check boot space
$ df -h /boot
Filesystem      Size  Used Avail Use% Mounted on
/dev/sda1       512M  128M  384M  25% /boot

# Verify GRUB works
$ sudo update-grub
Sourcing file `/etc/default/grub'
Generating grub configuration file ...
Found linux image: /boot/vmlinuz-5.15.0-84-generic
Found initrd image: /boot/initrd.img-5.15.0-84-generic

Lessons Learned

  1. Always keep current kernel + one fallback - never remove the running kernel.
  2. Use apt autoremove --purge for safest automatic cleanup.
  3. Monitor /boot space - it fills up faster than root partition.
  4. Update GRUB after manual removal to avoid boot menu errors.
  5. Test boot after cleanup - ensure the system boots correctly with remaining kernels.

This blog does not accept any external sponsorships, affiliate marketing, or ad revenue.