Wednesday, June 8, 2011

Stripping an Ubuntu system to just the basics...

WARNING: I am not responsible for you trashing your system. Use this guide with care. No attempt was made to ensure your intelligence level (nor mine).

UPDATE: Please read the comments about using apt-mark instead of the man-handler of a script that I have in the main post. Should lessen the chance of hosing your system.

While working on a cross-build system inside an Ubuntu 10.10 virtual machine instance, I decided I didn't want all the fluff of the desktop version. However, instead of just going through the entire package list on the machine, I came up with a quick way to have APT automatically handle it for me.

Ubuntu is nice in that it has meta-packages for the different levels of their system. The top-level meta-packages -- ubuntu-minimal, ubuntu-standard and ubuntu-desktop -- let APT know which package group to install (ubuntu-standard is generally used for server installs). APT also has the nice functionality of automatically being able to remove packages which were only installed because they were depended on by some other package. For example, if you install ffmpeg, you get a ton of libraries with it. If you then remove ffmpeg, you can run "apt-get autoremove" to also remove the libraries that are no longer needed because they were only installed to satisfy ffmpeg's dependencies.

So now, how to abuse this functionality. First, we find out how APT tracks these implicit/explicit package states (packages we installed directly vs. packages that were only installed to satisfy dependencies). We find /var/lib/apt/extended_states. The format is similar to /var/lib/dpkg/status and has stanzas in the form of:

Package: foo
Architecture: i386
Auto-Installed: 1

So here's a quick script that will mark all of your currently installed packages as auto-installed:


arch=$(dpkg --print-architecture)
dpkg --get-selections | awk '{print $1}' | \
(while read pkg; do
        echo "Package: $pkg"
        echo "Architecture: $arch"
        echo "Auto-Installed: 1"

Here's how we use it ( is the shell script from above):

sudo cp /var/lib/apt/extended_states /var/lib/apt/extended_states.bak
bash | sudo tee /var/lib/apt/extended_states > /dev/null 2>&1

Now, we have to tell APT that we want to keep some things. Personally, I went with the ubuntu-standard as a base line and added a few necessities for good measure. You could go with ubuntu-minimal, and also add packages here that you specifically want to keep (otherwise the commands later will remove them). Note, I specifically added grub-pc because a boot-loader is not a required package (think EC2, diskless installs, etc.). Be sure to add your boot-loader to this command if you require it.

sudo apt-get install ubuntu-standard grub-pc vim build-essential git

This most likely wont do much, since these packages are already installed. However, APT will mark them as "Auto-Installed: 0" so that it knows we explicitly installed them. Next, time to ditch a few hundred megs:

sudo apt-get --purge autoremove

This will take some time and finally spew out a huge list of things to remove. You may want to give it a quick once-over to make sure you aren't tossing something important. If you see a package you need, ^C out and run the apt-get install command again with the new package(s).

So now you should be clean and clear. Note that the above --purge option is meant to completely remove things like configuration files that were installed with the packages you are removing. If that scares you, then remove that option.


  1. I should point out that this also works if you've installed a bunch of things and want to go back to the fresh package list. So you could do this for the ubuntu-desktop meta-package too.

  2. Could you use 'aptitude markauto ".*"' instead of playing with /var/lib/apt/extended_states directly?

  3. @Marius, I've never used aptitude, but at first glance of aptitude(8) it sounds like it would do the trick.

  4. I do a similar thing with aptitude (the curses version) if i want to switch the DE. I go to 'Tasks' and purge (_) the whole package, then i go to another desktop (ubuntu-desktop, kubuntu-desktop, ubuntu-standard, ubuntu-minimal) and mark it as install (+). Then i let it run.
    Does basically the same thing, but gives me greater control because i can view the list of changes and change it without redoing everything.
    Worked fine the last couple of times i used it.

  5. @Marius Gedminas

    I'd use "apt-mark markauto" instead of "aptitude markauto" because apt-mark is installed by default whereas aptitude is not.

  6. should this line:

    sudo apt-get install boot-standard grub-pc vim build-essential git

    not be:
    sudo apt-get install ubuntu-standard grub-pc vim build-essential git


  7. You can also use debfoster to keep a text file list of packages you want to be installed.

  8. There's a complete set of commands using apt-mark to mark everything as automatically installed, to check proposed removals, and to retain mainstream packages via marking as 'manually installed', detailed at

    Roughly it amounts to the following to mark everything as automatically installed...

    aptitude --display-format '%p' search '~i!~M' | xargs -n100 sudo apt-mark auto

    ...this to check what will be removed given the current markings of packages as manual or automatic...

    sudo apt-get --simulate autoremove

    ...and this to add your selection of packages to keep as manually installed (including their dependencies). This example is from my Ubuntu Precise desktop, but others will retain different packages)

    sudo apt-mark manual ubuntu-desktop ubuntu-standard ubuntu-minimal language-pack-en-base language-pack-gnome-en language-pack-gnome-en-base libreoffice-help-en-gb thunderbird-locale-en-gb thunderbird-locale-en-us libreoffice-gnome libidl0 liborbit2 linux-headers-generic-pae hyphen-en-us installation-report linux-generic-pae mythes-en-au libreoffice-l10n-en-za linux-firmware-nonfree ubuntu-restricted-extras arduino geany gparted chromium-browser google-earth-stable google-chrome-stable synaptic

  9. Thank you Ben! Still works today!
    (Ubuntu Server 14.04 LTS)