Managing your software¶
If you are new to Ubuntu, you may be wondering what to do after installation. After all, Ubuntu is endlessly customisable according to your needs. There are two types of software found in Ubuntu: Debian packages and snaps – we will learn about both!
To help you get the most from your Ubuntu experience, this tutorial will walk you through managing the software on your Ubuntu machine. This tutorial can be completed using either Ubuntu Server or Ubuntu Desktop.
To avoid making changes to your computer we will set up a virtual machine (VM), which will provide us with a safe environment to run the commands in. Multipass is great for quickly creating Ubuntu virtual machines, so we will use that.
Prerequisites¶
Knowledge:
None! You don’t even need to use an Ubuntu machine – Multipass will give us an Ubuntu environment to play with.
Hardware:
The default Multipass VM will need 5 GiB of disk space, and 1 GiB of memory.
Software: – Multipass
On Ubuntu, you can install Multipass by running the following command in your terminal (you can open a terminal window by pressing Ctrl + Alt + T together):
sudo snap install multipass
Or you can install it directly from the Multipass page in the online snap store (make sure to select the “latest/stable” version from the dropdown menu next to the install button).
Multipass can be installed on Windows, Mac and other Linux distributions using these instructions.
Create the virtual machine¶
Once you have installed and run Multipass, it is straightforward to launch a
new VM. Let us launch a VM using the Ubuntu 24.04 LTS release (codename
noble
), and let’s give our VM the name tutorial
using the following
command in our terminal window:
multipass launch noble --name tutorial
Multipass will download the most recent daily image and create the VM for us. It may take a little time, depending on the speed of your internet connection.
An Ubuntu image is a collection of files we need to install and run Ubuntu. We don’t need to specify “server” or “desktop” anywhere in our command, because the image is the same for both. The only difference between Ubuntu Server and Ubuntu Desktop is the subset of software packages we use from the Ubuntu Archive - we will see this later!
Now we can access the VM by running:
multipass shell tutorial
We will get a “Welcome to Ubuntu” message. Notice that when we run
this command, the terminal username changes to ubuntu
and the hostname
changes to tutorial
:
ubuntu@tutorial
This shows that we are inside the VM, and this is where we will run all our commands.
Updating the system with APT¶
The first thing we always want to do with a new system (whether a VM, container, bare metal, or cloud instance) is to make sure we have the latest versions of all the pre-installed software.
Debian packages, commonly referred to as debs, are the standard software
package format in Ubuntu. They can be identified by the .deb
file extension.
Every Linux distribution has their own preferred package manager for installing, updating and removing packages. In Ubuntu, the default package manager is Advanced Packaging Tool (or APT, for short).
APT handles all of your system software (and other deb packages). It provides an interface to the Ubuntu Archive repository, so it can access both the database of all the packages available in Ubuntu, and the means to handle the packages themselves.
There are two APT commands we need to update our system: update
and
upgrade
, which we will always run in that order.
apt update¶
The apt update
command is about the database. Any bug fixes in a package
(or new versions since your last update) will be stored in the metadata about
that package in the database (the package index).
When we run the update
command it updates the APT database on our machine,
fetching the newest available metadata from the package index:
sudo apt update
We will see an output like this:
Hit:1 http://security.ubuntu.com/ubuntu noble-security InRelease
Hit:2 http://archive.ubuntu.com/ubuntu noble InRelease
Hit:3 http://archive.ubuntu.com/ubuntu noble-updates InRelease
Hit:4 http://archive.ubuntu.com/ubuntu noble-backports InRelease
Reading package lists... Done
Building dependency tree... Done
Reading state information... Done
88 packages can be upgraded. Run 'apt list --upgradable' to see them.
As we can see, it checks (“hits”) the various archives (pockets) that
updates can come from for the 24.04 LTS release (noble-security
, noble
,
noble-updates
and noble-backports
– remember these, as we’ll come back to
them later). It has found some packages that can be upgraded to newer versions.
If we want to see which packages those are, we can run the command hinted in
the output:
apt list --upgradable
The output tells us:
the package name and where the update will come from (e.g.
base-files/noble-updates
),the most up-to-date package version available (e.g.
13ubuntu10.1
)the hardware version the update is for (e.g.
amd64
), andwhat package version is currently installed (e.g.
13ubuntu10
)
The specific packages included in this list changes over time, so the exact packages shown will be different, but the output will be structured like this:
Listing... Done
base-files/noble-updates 13ubuntu10.1 amd64 [upgradable from: 13ubuntu10]
bsdextrautils/noble-updates 2.39.3-9ubuntu6.1 amd64 [upgradable from: 2.39.3-9ubuntu6]
bsdutils/noble-updates 1:2.39.3-9ubuntu6.1 amd64 [upgradable from: 1:2.39.3-9ubuntu6]
cloud-init/noble-updates 24.2-0ubuntu1~24.04.2 all [upgradable from: 24.1.3-0ubuntu3.3]
[...]
apt upgrade¶
The apt upgrade
command is about the packages on your system. It looks
at the metadata in the package index we just updated, finds the packages with
available upgrades, and lists them for us. Once we’ve checked the proposed
upgrade and are happy to proceed, it will then install the newer versions for
us.
After we have updated the database (which we did by running apt update
) we
can then upgrade the packages to their newest versions by running:
sudo apt upgrade
When we run this command, it will ask us to confirm if the summary of proposed changes that will be made to our system is what we want.
Let’s type Y, then press Enter to confirm that yes, we do want that, and then the upgrade will proceed. This may take a few minutes.
Tip
You can use the -y
flag, which is a shorthand for --assume-yes
. If we ran
the command sudo apt upgrade -y
it would proceed with the upgrade without
asking us to confirm. Shorthand versions of flags are common – for most
packages, you can check which flags are equivalent using
the manual pages or using the man
command, as we’ll see later.
In the output, we’ll see where apt upgrade
is fetching the upgrade from for
each package. For example:
Get:1 http://archive.ubuntu.com/ubuntu noble-updates/main amd64 libopeniscsiusr amd64 2.1.9-3ubuntu5.1 [49.1 kB]
APT combines the various elements; the package name (libopeniscsiusr
),
version (2.1.9-3ubuntu5.1
), source (noble-updates/main
), etc into a
single URL that it can use for the download. The package is then unpacked, and
the upgrade applied to the system.
Note
These commands only upgrade the packages for the release of Ubuntu that we
are using (24.04 LTS). If we wanted to upgrade the entire system to the
next release of Ubuntu (e.g. from 22.04 LTS to 24.04 LTS), we would use the
do-release-upgrade
command. See this guide on
how to upgrade your release for more information.
It’s important to know that apt upgrade
will only handle packages that can be
straightforwardly upgraded. If the package has dependency issues (i.e., the
version you have “depends” on other packages that also need to be added,
upgraded or removed), you would need to use sudo apt dist-upgrade
instead.
The dist-upgrade
command is able to resolve conflicts between package
versions, but it could end up removing some packages – so although
apt upgrade
is safe to use unattended (in a script, for example), you should
only use dist-upgrade
when you can pay attention to it.
Searching with APT¶
Now we’re up-to-date, we can start exploring! As with any other database, we can search the list of available packages using APT in order to find software. Let’s say that we want to find a webserver, for example. We can run the following command:
apt search webserver
This will return us a long list of all “webserver” packages it can find. But some of the descriptions don’t actually contain the text “webserver” – like in this section of the list:
inotify-tools/noble 3.22.6.0-4 amd64
command-line programs providing a simple interface to inotify
ipcalc/noble 0.51-1 all
parameter calculator for IPv4 addresses
iwatch/noble 0.2.2-10 all
realtime filesystem monitoring program using inotify
We can use apt show
to inspect the description and summary details of any
package, so let’s take a closer look at ipcalc
from our list:
apt show ipcalc
The summary has been replaced with [...]
for brevity, but we can see that the
text “webserver” is in the long description of the “Description” field.
Package: ipcalc
Version: 0.51-1
[...]
APT-Sources: http://archive.ubuntu.com/ubuntu noble/universe amd64 Packages
Description: parameter calculator for IPv4 addresses
ipcalc takes an IPv4 address and netmask and calculates the resulting
broadcast, network, Cisco wildcard mask, and host range. By giving a
second netmask, you can design sub- and supernetworks. It is also
intended to be a teaching tool and presents the results as
easy-to-understand binary values.
.
Originally, ipcalc was intended for use from the shell prompt, but a
CGI wrapper is provided to enable colorful HTML display through a
webserver.
You can find it in /usr/share/doc/ipcalc/examples directory.
In many places, you will see reference to apt-get
and apt-cache
instead
of apt
. Historically, the database part of APT was accessed using
apt-cache
(e.g. apt-cache show ipcalc
), and the packages part of APT
used apt-get
(e.g. apt-get install ipcalc
).
APT has recently been streamlined, so although it uses apt-get
and
apt-cache
“behind the scenes” (and these commands do still work), we don’t
need to worry about remembering which command to use – we can use the more
convenient apt
directly. To find out more about these packages and how to
use them (or indeed, any package in Ubuntu!) we can refer to the manual pages.
Run man apt
, man apt-get
or man apt-cache
in the terminal to access
the manuals for these packages on the command line, or view the same content in
the online manual pages.
Installing deb packages¶
For the examples for this section, we’re going to use the popular webserver package, Apache2.
APT gives us a lot of details about what will be included in the installation, and it’s always important to understand the implications of a command before we run it. We’ll be taking a close look at the details APT gives us, so we need to be careful in this section.
When we run a command that asks us “Do you want to continue? [Y/n]
”, make
sure to type N for “no” and then press Enter unless instructed
otherwise – this will let us see the output of the commands without making
changes that then need to be undone.
Installing deb packages using APT is done using the apt install
command.
We can install either a single package, or a list of packages at once, by
including their names in a space-separated list after the install
command,
in this format:
sudo apt install <package 1> <package 2> <package 3>
About sudo
¶
We’ve seen the sudo
prefix in a couple of commands already, and you may be
wondering what that’s about. In Linux, system tasks (like installing software)
need elevated administrator permissions. These permissions are often called
“root access”, and a user with root access is called a “root user”.
However, it can be dangerous to operate your machine as a root user – since root access gives you full system control the whole time, it allows you to change or delete important system files. It’s very easy to accidentally break your system in root mode!
Instead, we use sudo
(which is short for superuser do
). This command is
a safety feature that grants regular users temporary (per command) admin
privileges to make system changes. It’s still important for us to always
understand what a command does before we run it, but using sudo
means we
purposefully limit any potential mistakes to a single command.
About dependencies¶
As we hinted earlier, packages often come with dependencies – other
packages that your package needs so it can function. Sometimes, a package
might depend on a specific version of another package. If a package has
dependencies, then installing a package via apt
will also install any
dependencies, which ensures the software can function properly.
APT tells us how it will resolve any dependency conflicts or issues when we run
the install
command. Let’s try this for ourselves, but remember, we
don’t want to proceed with the install yet, so let’s type N when it
asks us if we want to continue:
sudo apt install apache2
The output should be similar to the below. It tells us:
which packages we have but don’t need (we’ll talk about that in the “autoremove” section),
additional packages that will be installed (these are our dependencies),
suggested packages (which we’ll discuss in the next section), and
a summary of which new packages will be present on the system after the install is done (which in this case is
apache2
itself, and all its dependencies).
Reading package lists... Done
Building dependency tree... Done
Reading state information... Done
The following additional packages will be installed:
apache2-bin apache2-data apache2-utils libapr1t64 libaprutil1-dbd-sqlite3 libaprutil1-ldap libaprutil1t64 liblua5.4-0 ssl-cert
Suggested packages:
apache2-doc apache2-suexec-pristine | apache2-suexec-custom www-browser
The following NEW packages will be installed:
apache2 apache2-bin apache2-data apache2-utils libapr1t64 libaprutil1-dbd-sqlite3 libaprutil1-ldap libaprutil1t64 liblua5.4-0 ssl-cert
0 upgraded, 10 newly installed, 0 to remove and 2 not upgraded.
Need to get 2084 kB of archives.
After this operation, 8094 kB of additional disk space will be used.
Do you want to continue? [Y/n]
Let’s try and make sense of this output.
Types of dependencies¶
The relationship between a package and any other packages follows the
Debian policy on binary dependencies,
which we’ll briefly look at here. The most common ones you might come
across are: depends
, recommends
, and suggests
(although there are
others!), so we’ll take a look at these three.
depends: Absolutely required, the package won’t work without it. If we try to remove a package that is depended on by another, both will be removed!
recommends: Strongly dependent, but not absolutely necessary (which means the package will work better with it, but can still function without it)
suggests: Not needed, but may enhance the usefulness of the package in some way.
We can see, using apt show
, exactly which packages fall into each of these
categories. Let’s use Apache2 as our example again:
apt show apache2
If we look only at the sections on dependencies, we can see that ssl-cert
is
a recommended package:
[...]
Provides: httpd, httpd-cgi
Pre-Depends: init-system-helpers (>= 1.54~)
Depends: apache2-bin (= 2.4.58-1ubuntu8.4), apache2-data (= 2.4.58-1ubuntu8.4), apache2-utils (= 2.4.58-1ubuntu8.4), media-types, perl:any, procps
Recommends: ssl-cert
Suggests: apache2-doc, apache2-suexec-pristine | apache2-suexec-custom, www-browser, ufw
[...]
In Ubuntu, the default configuration of apt install
is set to install
recommended packages alongside depends
, so when we ran the
apt install apache2
command, ssl-cert
was included in the proposed
packages to be installed (even though it’s only recommended, not strictly needed).
We can override this behaviour by passing the --no-install-recommends
flag to
our command, like this:
sudo apt install apache2 --no-install-recommends
Then the output becomes the following (type N at the prompt again to avoid installing for now):
[...]
The following additional packages will be installed:
apache2-bin apache2-data apache2-utils libapr1t64 libaprutil1-dbd-sqlite3 libaprutil1-ldap libaprutil1t64 liblua5.4-0
Suggested packages:
apache2-doc apache2-suexec-pristine | apache2-suexec-custom www-browser
Recommended packages:
ssl-cert
The following NEW packages will be installed:
apache2 apache2-bin apache2-data apache2-utils libapr1t64 libaprutil1-dbd-sqlite3 libaprutil1-ldap libaprutil1t64 liblua5.4-0
0 upgraded, 9 newly installed, 0 to remove and 25 not upgraded.
[...]
Now, we see that ssl-cert
is only mentioned as a recommended package, but
is excluded from the list of packages to be installed.
There is a second flag we could pass – the --install-suggests
flag. This
will not only install the strict dependencies and recommended packages, but
also the suggested packages. From our previous output, it doesn’t look like
too much, right? It’s only four additional packages.
But actually, if we run this command:
sudo apt install apache2 --install-suggests
There is now an extremely long list of suggested packages (which I will not output here, but you can try it for yourself!). In fact, the number of suggested packages is so long that there is not enough space in this VM to install them all, so it won’t even give us the option to proceed:
[...]
0 upgraded, 4598 newly installed, 2 to remove and 0 not upgraded.
Need to get 7415 MB of archives.
After this operation, 19.6 GB of additional disk space will be used.
E: You don't have enough free space in /var/cache/apt/archives/.
This is because each of these suggested packages also comes with their own lists of dependencies, including suggested packages, all of which would also be installed. It’s perhaps clear to see why this is not the default setting!
What if we remove a dependency?¶
We’ll go into more detail about removing packages later, but for now, let’s see
what happens if we remove a required dependency. First, we should (finally!)
install the apache2
package. Let’s run the following command again, but this
time when we are asked whether we want to continue, let’s press Y and
then Enter to confirm, and APT will install the package:
sudo apt install apache2
One of the required dependencies is the apache2-data
package. Let’s try to
remove it using apt remove
:
sudo apt remove apache2-data
Once again, apt
won’t proceed without confirmation, so we get the following
output – let’s take a look before choose anything:
[...]
The following packages were automatically installed and are no longer required:
apache2-bin apache2-utils libapr1t64 libaprutil1-dbd-sqlite3 libaprutil1-ldap libaprutil1t64 liblua5.4-0 ssl-cert
Use 'sudo apt autoremove' to remove them.
The following packages will be REMOVED:
apache2 apache2-data
0 upgraded, 0 newly installed, 2 to remove and 2 not upgraded.
After this operation, 1342 kB disk space will be freed.
Do you want to continue? [Y/n]
Let’s break this down a little bit, because there are some subtle differences here that we want to understand before we proceed.
“The following packages were automatically installed and are no longer required”
These were other dependencies that
apache2
needed, but none of them depend uponapache2-data
, so even if we removeapache2
andapache2-data
they would still be functional – they just aren’t used by any other installed packages…and so have no reason to be there anymore. They won’t be removed, APT is helpfully telling us so we’re aware of them.“The following packages will be REMOVED”
These are the packages that will be removed directly - we’ve told APT we want to remove
apache2-data
, so we expect that to be included, but it will also removeapache2
itself! This is becauseapache2-data
is a required dependency, andapache2
won’t function at all without it.
Let’s now choose Y to confirm we want to remove this dependency.
Warning
Removing dependencies can, at worst, cause a system to become unusable – you should always be careful when doing so. If you remove a dependency that is part of a chain, the removals will cascade up the chain as each dependency and the package that depends on it are removed. You can end up removing more than you originally anticipated!
Autoremove dependencies¶
So, we have removed the apache2
and apache2-data
packages, but the other
dependencies that were installed alongside apache2
are still there. The
output of our remove
command gave us the hint about how to deal with these
redundant packages – the autoremove
command:
sudo apt autoremove
When we run this command, apt
once again gives us a summary of the operation
we requested, but let’s choose N for now when it asks if we want to
continue:
[...]
The following packages will be REMOVED:
apache2-bin apache2-utils libapr1t64 libaprutil1-dbd-sqlite3 libaprutil1-ldap libaprutil1t64 liblua5.4-0 ssl-cert
0 upgraded, 0 newly installed, 8 to remove and 2 not upgraded.
After this operation, 6751 kB disk space will be freed.
Do you want to continue? [Y/n]
You may be wondering why we don’t need to specify any packages when we call the
autoremove
command – after all, we’ve just been dealing with packages
related to apache2
. This is because apt
will check all the packages on
your system. It examines the dependency tree, and if the original reason for the
package to be installed no longer exists (i.e., it isn’t needed by anything),
it will be flagged for autoremoval.
But!
We might, in the future, uninstall Apache2 without uninstalling the redundant
packages at the time. We might have found another use for ssl-cert
, perhaps
in a script that makes use of SSL certificates. So how can we keep the
ssl-cert
package, even though it’s flagged for autoremoval?
We can solve this problem, and un-flag the ssl-cert
package for removal, by
manually installing it:
sudo apt install ssl-cert
This sets ssl-cert
to manually installed. We might well wonder “why
didn’t APT didn’t ask us to confirm anything this time?”. In this case, it’s
because ssl-cert
is already present on the system so APT doesn’t need to
install anything new.
[...]
ssl-cert is already the newest version (1.1.2ubuntu1).
ssl-cert set to manually installed.
The following packages were automatically installed and are no longer required:
apache2-bin apache2-utils libapr1t64 libaprutil1-dbd-sqlite3 libaprutil1-ldap libaprutil1t64 liblua5.4-0
Use 'sudo apt autoremove' to remove them.
0 upgraded, 0 newly installed, 0 to remove and 2 not upgraded.
If the ssl-cert
package is manually installed on our system, by us, then
apt
knows the package is wanted, and we can see that it has been removed
from the autoremove list so our next autoremove will not uninstall it. Let’s
test this, just to make sure!
sudo apt autoremove
This time we’ll select Y when prompted, and then we can run
apt list ssl-cert
to quickly see if our ssl-cert
package is still on
the system:
apt list ssl-cert
Which gives us this output, confirming that ssl-cert
is currently installed:
Listing... Done
ssl-cert/noble,now 1.1.2ubuntu1 all [installed]
If you’re curious, you can also run apt list apache2
to see how the output
differs for a package that was once installed and then removed!
Anyway, we’re not quite finished with the Apache2 package, so let’s reinstall it:
sudo apt install apache2
And this time select Y to confirm when it asks.
Customise configuration¶
In general, the default package configuration should just work well, and work “out of the box” when it’s installed. But it’s almost inevitable that, sooner or later, we’ll want to customise the package so that it better fits our own purposes.
Before we try to customise the package, we should probably look at what files
are included in it. We can check this using dpkg
, which is the
Debian package manager.
Although APT is now more commonly used for basic package handling, dpkg
retains some really helpful commands for examining files and finding out
package information. It’s installed by default on Ubuntu systems so we can use
it directly:
dpkg --listfiles ssl-cert
This gives us the following list of files and their directory structure (the end of the list is truncated for brevity):
/.
/etc
/etc/ssl
/etc/ssl/certs
/etc/ssl/private
/lib
diverted by base-files to: /lib.usr-is-merged
/lib/systemd
/lib/systemd/system
/lib/systemd/system/ssl-cert.service
/usr
/usr/sbin
/usr/sbin/make-ssl-cert
/usr/share
/usr/share/doc
/usr/share/doc/ssl-cert
/usr/share/doc/ssl-cert/README
[...]
If we find a file but we’re not sure what package it comes from, dpkg
can
help us there too! Let’s use the example of one of the files from the previous
output: /usr/share/ssl-cert/ssleay.cnf
and do a search for it using
dpkg
:
dpkg --search /usr/share/ssl-cert/ssleay.cnf
This will provide us with the package name for the given file:
ssl-cert: /usr/share/ssl-cert/ssleay.cnf
Although this seems obvious to us, because we already know the source of this
file, the dpkg
search function is really useful for tracking down the
sources of files we don’t know about!
Conffiles¶
Most of a package’s configuration is handled through configuration files (often known as conffiles). Conffiles often contain things like file paths, logs and debugging configuration, kernel parameters (which can be changed to optimise system performance), access control, and other configuration settings. The actual parameters available will vary from one package to another.
Package conffiles are different from all other files delivered in a package. A package may have any number of conffiles (including none!). Conffiles are explicitly marked by the package maintainer during development to protect local configuration from being overwritten during upgrades so that your changes are saved. This is not the case for any other types of files – changes you make to regular files in that package will be overwritten during an upgrade.
How upgrades are handled¶
Since a conffile can be changed by us, we might end up with conflicts when the package maintainer changes those same files. Therefore, it’s important to understand how such conflicts are handled.
We can show the four possible upgrade scenarios using the following table. What happens during an upgrade depends on whether the conffile on our system has been changed by us (“changed/not changed by user”), and whether the version’s default content has been changed by the package maintainer (“changed/not changed by maintainer”):
The conffile is… |
not changed by maintainer |
changed by maintainer |
---|---|---|
…changed by user |
Keep user’s changes |
Ask user |
…not changed by user |
No changes to make |
Apply changes from update |
So we can see that if we do make changes to a conffile, APT will never overwrite our changes without asking us first.
Identifying conffiles¶
Out of the list of files in a package, how do we know which ones are the conffiles?
After all, they are not marked by any particular file extension, and
although they are often found in the /etc/
directory, they don’t have to
be there. As we saw before, the only thing conffiles have in common is that the
package maintainer decided to mark them as such.
But that’s our clue! So once more, dpkg
can come to our rescue. The
following command will show us (--show
) the subset of files in the
apache2
package that have been marked as “Conffiles
”
(-f='${Conffiles}\n'
) by the maintainer and shows each on a new line
(\n
) in the output:
dpkg-query --show -f='${Conffiles}\n' apache2
If you want to understand more about what this command does, you can refer to
the manual page by typing man dpkg-query --show
, and it will talk you
through all the options.
Unlike dpkg --listfiles
, dpkg-query
also gives us a string of letters
and numbers. This string is known as the “MD5 checksum” or “MD5 hash”.
/etc/apache2/apache2.conf 354c9e6d2b88a0a3e0548f853840674c
/etc/apache2/conf-available/charset.conf e6fbb8adf631932851d6cc522c1e48d7
/etc/apache2/conf-available/security.conf 332668933023a463046fa90d9b057193
/etc/apache2/envvars e4431a53c868ae0dfcde68564f3ce6a7
/etc/apache2/magic a6d370833a02f53db6a0a30800704994
[...]
We can see the checksum of a specific file by running this command:
md5sum /etc/apache2/apache2.conf
Which returns us the checksum followed by the file and its location:
354c9e6d2b88a0a3e0548f853840674c /etc/apache2/apache2.conf
You might well be wondering “why do we care about that?” since they match (in this example).
The checksum is like a fingerprint - it’s unique for every version of a file, so any time the file is changed it will get a new checksum – which allows us to see if a file has been changed from the default.
Verifying checksums¶
Let’s set up a situation so we can poke a bit at this idea. We can start by
making some changes to a conffile. In Apache2, the main conffile is
/etc/apache2/apache2.conf
, so let’s use that. In a situation where we are
setting up a new webserver, we might reasonably want to increase the
LogLevel
from “warn” to “debug” to get more debugging messages, so let’s
run this command and use sed
to make that change in the conffile:
sudo sed -e 's/LogLevel warn/LogLevel debug/' -i /etc/apache2/apache2.conf
We won’t be prompted to confirm if we want to make these changes – but we do
need root access so we use sudo
in our command. As we hinted in the section
about sudo
, the fact that we can make these changes without needing to
confirm is why it can be so easy to break your system when you’re operating as
root! Try running the command without the sudo
, and you will get a
“permission denied” error.
Next, we’ll restart our Apache2 server so that we can activate our configuration changes:
sudo systemctl restart apache2
Now if we run the md5sum
command again, we can see the hash changed:
ubuntu@tutorial:~$ md5sum /etc/apache2/apache2.conf
1109a77001754a836fb4a1378f740702 /etc/apache2/apache2.conf
This works great if we know that there’s a file we changed, but what about if someone else tampered with a file, and we don’t know which one? In that case, we can use:
dpkg --verify apache2
This will verify the checksums of the files on our system against those held in
the package index for apache2
, and return a rather strange looking result
if (or when) it finds a mismatch:
??5?????? c /etc/apache2/apache2.conf
Which is exactly what we were expecting to see, since we know we changed this file.
But what if something else was messed with…something that shouldn’t be, and something not changed by us? Let’s make a “silly” change to a different file to test this – in this case, changing all instances of the word “warning” to “silly” in a random package file:
sudo sed -e 's/warning/silly/' -i /usr/sbin/a2enmod
And then run the verification again with:
dpkg --verify apache2
We now see something that looks like this:
??5?????? c /etc/apache2/apache2.conf
??5?????? /usr/sbin/a2enmod
Note
You might have noticed there’s a “c” next to the top line but not the bottom – the “c” shows the file is a conffile.
dpkg
can tell that the file has been changed, but won’t tell us what the
change was. However, since the file in question is not a conffile, we know that
the change won’t be preserved if we upgrade the package. This means that we
can overwrite the changes and restore the default package content by
“reinstalling” Apache2:
sudo apt install --reinstall apache2
By using the --reinstall
flag, we can force apt
to re-unpack all of the
default content. If we then verify once more…
dpkg --verify apache2
Then we’ll get this output:
??5?????? c /etc/apache2/apache2.conf
…so we can see that our change to the conffile has been preserved because
the checksums are different, but the a2enmod
file isn’t listed anymore
because it has been restored to the default. Phew!
Note
We can use sudo apt install <package>
to upgrade an installed package,
but this will only upgrade to the latest version. In our case, we were
already on the latest version of Apache2, so we needed to force APT to
re-unpack the content to overwrite our “silly” changes.
Removing packages¶
Since we have just reinstalled the Apache2 package, we know it is in good shape. But what if we decide we’re done with it and just want to remove it? Then we can run:
sudo apt remove apache2
Which will give us an output like this:
Reading package lists... Done
Building dependency tree... Done
Reading state information... Done
The following packages were automatically installed and are no longer required:
apache2-bin apache2-data apache2-utils libapr1t64 libaprutil1-dbd-sqlite3
libaprutil1-ldap libaprutil1t64 liblua5.4-0
Use 'sudo apt autoremove' to remove them.
The following packages will be REMOVED:
apache2
0 upgraded, 0 newly installed, 1 to remove and 44 not upgraded.
After this operation, 465 kB disk space will be freed.
Do you want to continue? [Y/n]
Let’s type Y to proceed.
As before, we see that the dependencies will still be there even when
apache2
has been removed. Let’s check with dpkg
…
dpkg --listfiles apache2
…and see what else might be left behind…
/etc
/etc/apache2
/etc/apache2/apache2.conf
/etc/apache2/conf-available
/etc/apache2/conf-available/charset.conf
/etc/apache2/conf-available/localized-error-pages.conf
/etc/apache2/conf-available/other-vhosts-access-log.conf
/etc/apache2/conf-available/security.conf
/etc/apache2/conf-available/serve-cgi-bin.conf
/etc/apache2/conf-enabled
/etc/apache2/envvars
/etc/apache2/magic
/etc/apache2/mods-available
/etc/apache2/mods-available/access_compat.load
/etc/apache2/mods-available/actions.conf
[...]
This looks suspiciously like the list of conffiles we saw earlier, right?
Also removing configuration¶
As it turns out, removing a package doesn’t automatically remove the conffiles. But – this is intentional, for our convenience.
By leaving the conffiles in place, if we decide to reinstall apache2
again
in the future, we don’t need to spend time setting up all our configuration
again.
Let’s see the difference in installing apache2
after it has been installed
(and removed) compared to the first time we installed it:
sudo apt install apache2
Notice that it did not ask us to confirm if we wanted to proceed this time. Why not? As we saw earlier, the “Y/n” confirmation is shown when there are dependencies, and we know that Apache2 has dependencies.
…Ah! But this time, we didn’t run autoremove
when we uninstalled Apache2,
so the dependencies are still installed on our system. This means that when we
ask apt
to install apache2
now, there is nothing missing and we are
getting exactly what we are asking for.
Since the dependencies and conffiles are still there, we can use our former config immediately. It even retains the changes we made before, which we can verify by looking at the checksum again:
md5sum /etc/apache2/apache2.conf
Removing and purging¶
What if we decide that we don’t want the changed conffiles? Perhaps we want to go back to the default installation, or we know we won’t want to use the package ever again – how can we ensure that all the conffiles are removed at the same time as we remove the package?
In that case, we can use the --purge
option of the remove
command:
sudo apt remove --purge apache2
Which will give us this output:
[...]
The following packages were automatically installed and are no longer required:
apache2-bin apache2-data apache2-utils libapr1t64 libaprutil1-dbd-sqlite3
libaprutil1-ldap libaprutil1t64 liblua5.4-0
Use 'sudo apt autoremove' to remove them.
The following packages will be REMOVED:
apache2*
0 upgraded, 0 newly installed, 1 to remove and 9 not upgraded.
After this operation, 465 kB disk space will be freed.
Do you want to continue? [Y/n]
If we look very carefully, we see a little asterisk (*) in the output.
The following packages will be REMOVED:
apache2*
This tiny indicator tells us that the package will be removed AND purged. However, it still does not remove the dependencies (or the conffiles of those dependencies).
Let’s type Y again to confirm we want to proceed. Then, once the removal is complete, we can check the list once more:
dpkg --listfiles apache2
And this time, the output is very different!
dpkg-query: package 'apache2' is not installed
Use dpkg --contents (= dpkg-deb --contents) to list archive files contents.
Note
We could also use the dpkg-query --show -f='${Conffiles}\n' apache2
command from earlier, and dpkg-query
will find no packages matching
apache2
.
There are other ways to change package files. If you would like to read more, check out our guide to changing package files.
What else is on our system?¶
As we saw earlier, we can search the APT package database for keywords using
apt search <keyword>
to find software we might want to install. We can also
see all the packages we already have using apt list
, although it can be
easier to navigate and more informative if we use dpkg -l
instead – then
we can use the up and down arrow keys on our keyboard to scroll (or press
Q to return to our terminal prompt).
For every package, we can see what versions of it exist in the database:
apt policy apache2
This will return a summary of all the versions that exist on our particular Ubuntu release, ordered by “most recent” first:
apache2:
Installed: (none)
Candidate: 2.4.58-1ubuntu8.4
Version table:
2.4.58-1ubuntu8.4 500
500 http://archive.ubuntu.com/ubuntu noble-updates/main amd64 Packages
500 http://security.ubuntu.com/ubuntu noble-security/main amd64 Packages
100 /var/lib/dpkg/status
2.4.58-1ubuntu8 500
500 http://archive.ubuntu.com/ubuntu noble/main amd64 Packages
We know that Apache2 isn’t installed right now, because we removed and purged it, which is why the installed version shows as “none”:
Installed: (none)
If we were to install the default package, we would get this one:
Candidate: 2.4.58-1ubuntu8.4
Under each version we are also shown the source. The newest version
(2.4.58-1ubuntu8.4
) comes from noble-updates
(main) and
noble-security
(main). The original version (2.4.58-1ubuntu8
) comes
from noble
(main). This tells us that this was the version released with
the with 24.04 LTS (Noble Numbat).
Installing older package versions¶
We can install specific older versions if we want to, for example, to satisfy dependency requirements of another package. We can do that by specifying the package name and version:
sudo apt install <package=version>
However, this can be tricky and often leads to conflicts in dependency versions as APT always wants to install the most recent version. We can see an example of this if we run the following command:
sudo apt install apache2=2.4.58-1ubuntu8
APT warns us that the version of apache2 we want to install depends on earlier versions of the dependencies, but it helpfully tells us which dependency versions we need to successfully install the package we want.
[...]
Some packages could not be installed. This may mean that you have
requested an impossible situation or if you are using the unstable
distribution that some required packages have not yet been created
or been moved out of Incoming.
The following information may help to resolve the situation:
The following packages have unmet dependencies:
apache2 : Depends: apache2-bin (= 2.4.58-1ubuntu8) but 2.4.58-1ubuntu8.4 is to be installed
Depends: apache2-data (= 2.4.58-1ubuntu8) but 2.4.58-1ubuntu8.4 is to be installed
Depends: apache2-utils (= 2.4.58-1ubuntu8) but 2.4.58-1ubuntu8.4 is to be installed
E: Unable to correct problems, you have held broken packages.
So, all we need to do is first install the dependencies, and then run the install command again. Remember that we can install multiple packages at once by separating them with spaces:
sudo apt install apache2-bin=2.4.58-1ubuntu8 \
apache2-data=2.4.58-1ubuntu8 \
apache2-utils=2.4.58-1ubuntu8 \
apache2=2.4.58-1ubuntu8
In this case we’re also breaking the command over multiple lines using
backslashes (\
) to make it easier to read, but it will still be run as a
single command.
APT will warn us that we are downgrading the package, but let us press Y to confirm (when prompted), and it will go ahead and downgrade us anyway. Let’s run the following command again:
apt policy apache2
And we’ll get confirmation that we’re running on an older version:
apache2:
Installed: 2.4.58-1ubuntu8
Candidate: 2.4.58-1ubuntu8.4
Version table:
2.4.58-1ubuntu8.4 500
500 http://archive.ubuntu.com/ubuntu noble-updates/main amd64 Packages
500 http://security.ubuntu.com/ubuntu noble-security/main amd64 Packages
*** 2.4.58-1ubuntu8 500
500 http://archive.ubuntu.com/ubuntu noble/main amd64 Packages
100 /var/lib/dpkg/status
Where do packages come from?¶
You may be wondering by now “where exactly do all these packages come from?”. We’ve spotted a few sources very briefly throughout this tutorial, but haven’t paid direct attention to them yet. Let’s take a little time now to define what we mean by all these different sources that APT can pull packages from.
The source behind APT is the Ubuntu Package Archive. This Archive splits into many layers, each with its own terminology. The different terminology is quite confusing at first, but we’ve seen a few of the terms already. So if we take a look, layer-by-layer, we’ll see not just what all the terms mean, but how they all fit together.
Let’s have a quick overview with this diagram. The general flow is that the Archive splits into Ubuntu series. Each series is split up into pockets, and then each pocket contains four components. If we tried to show all of this on one diagram, it would be quite extensive, so let’s take a look through a single path.
flowchart TD; A[Ubuntu Package Archive] --> B([Splits into Ubuntu **series**]); B --> C[e.g., mantic]; B --> D[noble]; B --> E[oracular, etc]; D --> H([Series split into **pockets**]); H --> I[-release]; H --> J[-proposed]; H --> K[-updates]; H --> L[-security]; H --> M[-backports]; K --> N([Splits into **components**]); N --> O[main]; N --> P[universe]; N --> Q[restricted]; N --> R[multiverse]; style C fill:#fff,stroke:#cfcfcf,stroke-width:2px; style D fill:#fff,stroke:#cfcfcf,stroke-width:2px; style E fill:#fff,stroke:#cfcfcf,stroke-width:2px; style I fill:#fff,stroke:#cfcfcf,stroke-width:2px; style J fill:#fff,stroke:#cfcfcf,stroke-width:2px; style K fill:#fff,stroke:#cfcfcf,stroke-width:2px; style L fill:#fff,stroke:#cfcfcf,stroke-width:2px; style M fill:#fff,stroke:#cfcfcf,stroke-width:2px; style O fill:#fff,stroke:#cfcfcf,stroke-width:2px; style P fill:#fff,stroke:#cfcfcf,stroke-width:2px; style Q fill:#fff,stroke:#cfcfcf,stroke-width:2px; style R fill:#fff,stroke:#cfcfcf,stroke-width:2px;
Series¶
The series is a set of packages that are released with a specific version
of Ubuntu – they’re usually referred to by their codename (e.g., mantic
,
noble
and oracular
in our diagram). Each version of Ubuntu may have
multiple releases (for example, an LTS will have an initial release when it
launches (e.g. 24.04 LTS), and then “subsequent point releases” (e.g. 24.04.1
LTS) – these are all part of the same series (noble
).
In practice, people often use the term “Ubuntu release” and “Ubuntu series” interchangeably.
Pockets¶
Every Ubuntu series (noble
, jammy
, etc) is split into pockets,
which are related to the software development/release lifecycle:
-release contains the packages as they are at release time.
-proposed contains package updates while they are being tested.
Once an update is released, they come from either -security or -updates depending on whether they are a security-related update or not.
And -backports, which contains packages that were not available at release time.
This is why earlier, we saw that some updates came from noble-updates
or
noble-security
. These refer to updates and security updates from the noble
series (respectively). Pockets are usually appended to the end of the series,
and it’s quite common to see the hyphen (-
) included when referring to
pockets.
Remember – the original version of the apache2
package we saw came from
noble
. The -release
pocket only includes the software that was part of
the original LTS release, and so it takes the name of the Ubuntu series by
default (i.e., the -release
pocket is implied).
Components¶
Each pocket is split into four components, depending on whether the packages they contain are open source or closed source, and whether they are officially supported by Canonical or are maintained by the Ubuntu Community:
Open source |
Closed source |
|
---|---|---|
Officially supported |
main |
restricted |
Community supported |
universe |
multiverse |
main contains the open-source packages that are officially supported by Canonical. These packages are either installed on every Ubuntu machine, or are very widely used for various types of systems and use-cases.
universe holds all other open-source packages in Ubuntu, which are typically maintained by the Debian and Ubuntu communities, but may also include additional security coverage from Canonical under Ubuntu Pro, which is available free for personal use on up to five machines.
restricted contains the packages that are officially supported by Canonical but are not available under a completely free license.
multiverse contains community-maintained proprietary software – these packages are completely unsupported by Canonical.
If you would like more information about the Ubuntu release process, how packages are produced, or to learn more about the sort of terminology you might come across, you may be interested in the Ubuntu Packaging Guide, which is a great resource containing all this information (and much more!).
Installing a .deb file¶
Although APT is the preferred way to install packages on your system, due to its ability to handle depedencies and keep software up-to-date, not every package is available in the APT repository – especially if they are so old they are no longer maintained, or conversely, are the newest version still in development!
We can install .deb files that aren’t in the APT repository using dpkg
–
all we need is to download the .deb file, and we can run a command like this to
install it:
sudo dpkg -i <file-name.deb>
But – APT is helpful here too. Even if we get a .deb file that isn’t from the Ubuntu Archive, we can still install it with APT so that if there are dependencies that can be resolved automatically from the Archive – they will be!
sudo apt install ./file-name.deb
If we ever do want to install a .deb file, APT is definitely the most convenient way to do it. We may still need to handle some dependencies manually, but now we have the knowledge to be able to do that.
Luckily, most of the packages you will ever need are likely to be found through APT. If it’s not, it’s worth checking if the software is available as a snap instead.
Snaps¶
Snaps are a newer, self-contained software format that were developed to be a more portable and easy-to-use alternative to debs. They come with all their dependencies pre-bundled so that there is no need for a package management tool to track dependencies, and they run inside sandboxed environments that limit their interactions with the rest of the system.
Instead of versions as we have them in debs, snaps use the concept of channels to define which release of a snap is installed.
By default, snaps are kept automatically up-to-date, so we don’t need to remember to update and upgrade them. There are times on a live system, such as a server in a production environment, where we might not want to have updates automatically applied. In those cases, we can turn off automatic updates and refresh the system snaps when it’s convenient (for example, during a maintenance window).
If you would like to try out snaps, we recommend the excellent quickstart tour tutorial in the snap documentation. Feel free to continue using the VM we’ve been using in this tutorial while exploring!
Completion!¶
Once you are finished and want to leave the tutorial, you can run:
exit
This will take you out of the VM and back to your live machine. Then, you can run the following commands to delete the VM and remove it completely from your machine:
multipass delete tutorial
multipass purge
Summary¶
Congratulations, we made it to the end! We’ve covered a lot of material in this tutorial, so let’s do a quick recap of what we’ve learned:
Finding, installing and removing packages
How to update and upgrade all our system’s software with APT: *
sudo apt update && sudo apt upgrade
How to search for software using keywords or strings: *
apt search <keyword>
orapt search "some content string"
How to see the description of a package, including what dependencies it has: *
apt show <package name>
Or how to check what package versions are available: *
apt policy <package>
How to install packages… *
sudo apt install <package1> <package2>
How to see all the files a package contains *
dpkg --listfiles <package>
How to find out what package a file belongs to: *
dpkg --search <path/to/file>
…And how to remove packages again! As well as the difference between removing and purging. *
sudo apt remove <package>
We even learned how to downgrade to older versions of APT packages, and all about APT sources.
Customising package configuration
How to find the conffiles in a package: *
dpkg-query --show -f='${Conffiles}\n' <package>
How to see if package files have been changed: *
dpkg --verify <package>
…And if a non-conffile has been changed by accident, we can fix it with: *
sudo apt install --reinstall <package>
We know that our changes to conffiles are always safely preserved, while changes to non-conffiles are reverted at the next upgrade or security fix.
Importantly, we know how to verify checksums with
md5sum
or similar tools, which helps us to more safely build packages from source.And finally, we learned about snaps!