📦 Lesson 6: Installing Software with apt

How Ubuntu installs, updates and removes software, why "apt update" comes first, and a first real use of sudo

Video: Installing Software with apt on Ubuntu (Linux 101 video)
Prefer to watch? This short video runs the lesson's main commands on a real Ubuntu 24.04 machine, with on-screen captions and no voiceover. Click to play, or watch it on YouTube.

Software comes from repositories

On Linux you do not usually go to a website, download an installer and click Next. Instead, your distribution runs repositories: big, signed collections of software that your computer can fetch from. Each program, together with the files it needs, is bundled into a package. The tool that finds, downloads and installs packages on Ubuntu is called apt. It is the Linux equivalent of an app store, with the big advantage that everything it installs is checked and kept up to date together.

Where does your machine look? In a settings file. This is the real one from the practice machine, with the explanatory comments left out (we used grep -v '^#' from lesson 4, which shows every line that does not start with a hash):

root@practice:/# grep -v '^#' /etc/apt/sources.list.d/ubuntu.sources

Types: deb
URIs: http://archive.ubuntu.com/ubuntu/
Suites: noble noble-updates noble-backports
Components: main universe restricted multiverse
Signed-By: /usr/share/keyrings/ubuntu-archive-keyring.gpg

Types: deb
URIs: http://security.ubuntu.com/ubuntu/
Suites: noble-security
Components: main universe restricted multiverse
Signed-By: /usr/share/keyrings/ubuntu-archive-keyring.gpg

The administrator prompt

Installing software changes the whole machine, so it needs administrator rights. For most of this lesson, use a practice machine that runs as root, as in lesson 5: docker run -it --rm --hostname practice ubuntu:24.04. Its prompt ends in #. On a normal Ubuntu you stay an ordinary user and put sudo in front of each apt command instead, and we do exactly that at the end of this lesson.

The first mistake everyone makes

We want the less viewer that lesson 4 promised. Try the obvious thing:

root@practice:/# apt install less
Reading package lists... Done
Building dependency tree... Done
Reading state information... Done
Package less is not available, but is referred to by another package.
This may mean that the package is missing, has been obsoleted, or
is only available from another source

E: Package 'less' has no installation candidate

"Package 'less' has no installation candidate." Is less missing from Ubuntu? No. Your machine keeps a local catalog of what is available, and on this brand-new practice machine that catalog is empty, so as far as it knows, there is no such package. (On a real computer the catalog is usually there but out of date, which causes the same kind of puzzling "not found" errors.) The fix is the command you will type more than any other:

apt update: refresh the catalog

root@practice:/# apt update
Get:1 http://security.ubuntu.com/ubuntu noble-security InRelease [126 kB]
Get:2 http://archive.ubuntu.com/ubuntu noble InRelease [256 kB]
Get:3 http://security.ubuntu.com/ubuntu noble-security/main amd64 Packages [1318 kB]
Get:4 http://archive.ubuntu.com/ubuntu noble-updates InRelease [126 kB]
Get:5 http://archive.ubuntu.com/ubuntu noble-backports InRelease [126 kB]
Get:6 http://archive.ubuntu.com/ubuntu noble/multiverse amd64 Packages [331 kB]
Get:7 http://archive.ubuntu.com/ubuntu noble/restricted amd64 Packages [117 kB]
Get:8 http://archive.ubuntu.com/ubuntu noble/main amd64 Packages [1808 kB]
Get:9 http://archive.ubuntu.com/ubuntu noble/universe amd64 Packages [19.3 MB]
Get:10 http://security.ubuntu.com/ubuntu noble-security/restricted amd64 Packages [1943 kB]
Get:11 http://archive.ubuntu.com/ubuntu noble-updates/restricted amd64 Packages [2131 kB]
Get:12 http://archive.ubuntu.com/ubuntu noble-updates/multiverse amd64 Packages [56.2 kB]
Get:13 http://archive.ubuntu.com/ubuntu noble-updates/universe amd64 Packages [2162 kB]
Get:14 http://security.ubuntu.com/ubuntu noble-security/multiverse amd64 Packages [50.0 kB]
Get:15 http://archive.ubuntu.com/ubuntu noble-updates/main amd64 Packages [1690 kB]
Get:16 http://security.ubuntu.com/ubuntu noble-security/universe amd64 Packages [1542 kB]
Get:17 http://archive.ubuntu.com/ubuntu noble-backports/multiverse amd64 Packages [671 B]
Get:18 http://archive.ubuntu.com/ubuntu noble-backports/universe amd64 Packages [36.0 kB]
Get:19 http://archive.ubuntu.com/ubuntu noble-backports/main amd64 Packages [49.0 kB]
Fetched 33.2 MB in 4s (8850 kB/s)
Reading package lists... Done
Building dependency tree... Done
Reading state information... Done
3 packages can be upgraded. Run 'apt list --upgradable' to see them.

Each Get: line is the machine downloading one catalog file. apt update installs nothing and upgrades nothing: it only refreshes the list of what is available. It fetched 33.2 MB, which is why a fresh container takes a few seconds. The last line tells you that 3 installed packages have newer versions available. Run apt update before any install, and any time apt says it cannot find something.

Search and look before you install

root@practice:/# apt search --names-only '^tree$'
Sorting... Done
Full Text Search... Done
tree/noble-updates 2.1.1-2ubuntu3.24.04.2 amd64
  displays an indented directory tree, in color

root@practice:/# apt-cache policy tree
tree:
  Installed: (none)
  Candidate: 2.1.1-2ubuntu3.24.04.2
  Version table:
     2.1.1-2ubuntu3.24.04.2 500
        500 http://archive.ubuntu.com/ubuntu noble-updates/universe amd64 Packages
     2.1.1-2ubuntu3 500
        500 http://archive.ubuntu.com/ubuntu noble/universe amd64 Packages

Install a package

root@practice:/# apt install -y tree
Reading package lists... Done
Building dependency tree... Done
Reading state information... Done
The following NEW packages will be installed:
  tree
0 upgraded, 1 newly installed, 0 to remove and 3 not upgraded.
Need to get 47.4 kB of archives.
After this operation, 111 kB of additional disk space will be used.
Get:1 http://archive.ubuntu.com/ubuntu noble-updates/universe amd64 tree amd64 2.1.1-2ubuntu3.24.04.2 [47.4 kB]
Fetched 47.4 kB in 1s (49.5 kB/s)
debconf: delaying package configuration, since apt-utils is not installed

Selecting previously unselected package tree.
(Reading database ... 4381 files and directories currently installed.)
Preparing to unpack .../tree_2.1.1-2ubuntu3.24.04.2_amd64.deb ...
Unpacking tree (2.1.1-2ubuntu3.24.04.2) ...
Setting up tree (2.1.1-2ubuntu3.24.04.2) ...
root@practice:/# which tree
/usr/bin/tree
root@practice:/# tree -L 1 /usr
/usr
|-- bin
|-- games
|-- include
|-- lib
|-- lib64
|-- libexec
|-- local
|-- sbin
|-- share
`-- src

11 directories, 0 files
root@practice:/# dpkg -L tree
/.
/usr
/usr/bin
/usr/bin/tree
/usr/share
/usr/share/doc
/usr/share/doc/tree
/usr/share/doc/tree/README.gz
/usr/share/doc/tree/TODO
/usr/share/doc/tree/changelog.Debian.gz
/usr/share/doc/tree/copyright
/usr/share/man
/usr/share/man/man1
/usr/share/man/man1/tree.1.gz

Dependencies: one install, many packages

Programs are built from shared pieces, so installing one package often installs others it needs. Those are called dependencies, and apt works them out for you:

root@practice:/# apt install -y less curl
Reading package lists... Done
Building dependency tree... Done
Reading state information... Done
The following additional packages will be installed:
  ca-certificates krb5-locales libbrotli1 libcurl4t64 libgssapi-krb5-2
  libk5crypto3 libkeyutils1 libkrb5-3 libkrb5support0 libldap-common libldap2
  libnghttp2-14 libpsl5t64 librtmp1 libsasl2-2 libsasl2-modules
  libsasl2-modules-db libssh-4 libssl3t64 openssl publicsuffix
Suggested packages:
  krb5-doc krb5-user libsasl2-modules-gssapi-mit
  | libsasl2-modules-gssapi-heimdal libsasl2-modules-ldap libsasl2-modules-otp
  libsasl2-modules-sql
The following NEW packages will be installed:
  ca-certificates curl krb5-locales less libbrotli1 libcurl4t64
  libgssapi-krb5-2 libk5crypto3 libkeyutils1 libkrb5-3 libkrb5support0
  libldap-common libldap2 libnghttp2-14 libpsl5t64 librtmp1 libsasl2-2
  libsasl2-modules libsasl2-modules-db libssh-4 openssl publicsuffix
The following packages will be upgraded:
  libssl3t64
1 upgraded, 22 newly installed, 0 to remove and 2 not upgraded.
Need to get 5645 kB of archives.
After this operation, 9485 kB of additional disk space will be used.
[... the middle of the output is left out to keep this page short ...]
Processing triggers for libc-bin (2.39-0ubuntu8.9) ...
Processing triggers for ca-certificates (20260601~24.04.1) ...
Updating certificates in /etc/ssl/certs...
0 added, 0 removed; done.
Running hooks in /etc/ca-certificates/update.d...
done.
root@practice:/# command -v less curl
/usr/bin/less
/usr/bin/curl

We asked for two packages, less and curl. apt listed 22 additional ones that curl needs (security libraries, certificates, and more), upgraded one that was already installed, and downloaded 5645 kB in total. You never have to know the list. In the part of the output left out above, a bare container prints several lines that start with debconf: and say that it cannot start a friendlier screen (for example "unable to initialize frontend: Readline"). They look like errors and are harmless: the install carries on and finishes. The same machine can now use both programs:

Remove software

root@practice:/# apt remove -y tree
Reading package lists... Done
Building dependency tree... Done
Reading state information... Done
The following packages will be REMOVED:
  tree
0 upgraded, 0 newly installed, 1 to remove and 2 not upgraded.
After this operation, 111 kB disk space will be freed.

(Reading database ... 5013 files and directories currently installed.)
Removing tree (2.1.1-2ubuntu3.24.04.2) ...
root@practice:/# which tree

apt remove took tree off the machine and freed 111 kB. Afterwards which tree prints nothing, which is exactly how you know it is gone. There is also apt purge, which removes the package and its settings files, and apt autoremove, which cleans out dependencies nobody needs any more (from the documentation, not run here).

Keeping the whole system up to date

Software gets bug and security fixes constantly. After apt update, this command lists what is waiting:

root@practice:/# apt list --upgradable
Listing... Done
libaudit-common/noble-updates 1:3.1.2-2.1ubuntu0.1 all [upgradable from: 1:3.1.2-2.1build1.1]
libaudit1/noble-updates 1:3.1.2-2.1ubuntu0.1 amd64 [upgradable from: 1:3.1.2-2.1build1.1]
libssl3t64/noble-updates,noble-security 3.0.13-0ubuntu3.16 amd64 [upgradable from: 3.0.13-0ubuntu3.15]

Three installed packages have newer versions. To install all the waiting updates, you run sudo apt update and then sudo apt upgrade (from the documentation, not run here, because it would change the practice machine). Doing this regularly is the single most useful thing you can do to keep a Linux machine safe.

Using sudo for real

Now the part you have been waiting for. A normal user is not allowed to install software. Here is a normal user trying, and what happens. First we install sudo itself on the root practice machine and give the ubuntu user a password for practice (chpasswd sets it, and the | pipe is explained in lesson 11, so just copy it for now). Then su - ubuntu switches to the ordinary user, which prints Ubuntu's friendly reminder about sudo:

root@practice:/# apt install -y sudo
Reading package lists... Done
Building dependency tree... Done
Reading state information... Done
The following additional packages will be installed:
  libapparmor1
The following NEW packages will be installed:
  libapparmor1 sudo
0 upgraded, 2 newly installed, 0 to remove and 3 not upgraded.
Need to get 1000 kB of archives.
After this operation, 3678 kB of additional disk space will be used.
Get:1 http://archive.ubuntu.com/ubuntu noble-updates/main amd64 libapparmor1 amd64 4.0.1really4.0.1-0ubuntu0.24.04.8 [51.4 kB]
Get:2 http://archive.ubuntu.com/ubuntu noble-updates/main amd64 sudo amd64 1.9.15p5-3ubuntu5.24.04.3 [949 kB]
[... the middle of the output is left out to keep this page short ...]

root@practice:/# echo 'ubuntu:practice' | chpasswd
root@practice:/# su - ubuntu
To run a command as administrator (user "root"), use "sudo <command>".
See "man sudo_root" for details.

ubuntu@practice:~$ ls /root
ls: cannot open directory '/root': Permission denied
ubuntu@practice:~$ apt install tree
E: Could not open lock file /var/lib/dpkg/lock-frontend - open (13: Permission denied)
E: Unable to acquire the dpkg frontend lock (/var/lib/dpkg/lock-frontend), are you root?
ubuntu@practice:~$ sudo !!
sudo apt install tree
[sudo] password for ubuntu:
Reading package lists... Done
Building dependency tree... Done
Reading state information... Done
The following NEW packages will be installed:
  tree
0 upgraded, 1 newly installed, 0 to remove and 3 not upgraded.
Need to get 47.4 kB of archives.
After this operation, 111 kB of additional disk space will be used.
Get:1 http://archive.ubuntu.com/ubuntu noble-updates/universe amd64 tree amd64 2.1.1-2ubuntu3.24.04.2 [47.4 kB]
Fetched 47.4 kB in 1s (73.7 kB/s)
debconf: delaying package configuration, since apt-utils is not installed

Selecting previously unselected package tree.
(Reading database ... 4454 files and directories currently installed.)
Preparing to unpack .../tree_2.1.1-2ubuntu3.24.04.2_amd64.deb ...
Unpacking tree (2.1.1-2ubuntu3.24.04.2) ...
Setting up tree (2.1.1-2ubuntu3.24.04.2) ...
ubuntu@practice:~$ sudo ls -a /root
.  ..  .bashrc	.profile

Look at what happened:

  1. ls /root failed: Permission denied, as in lesson 5.
  2. apt install tree failed too, with a clear message: it cannot take the lock that only the administrator can take, and it even asks "are you root?".
  3. sudo !! fixed it. You met !! in lesson 2: "run the last command again". Here it became sudo apt install tree, which is the command with sudo in front.
  4. sudo asked [sudo] password for ubuntu:. It asks for your own password, to prove it is really you at the keyboard, and typing it shows nothing on the screen, not even dots. That is normal.
  5. The command then ran with full administrator rights, and tree was installed.
  6. The next sudo ls -a /root did not ask for the password again. sudo remembers that you proved yourself for a short time (15 minutes by default), and it showed the hidden files in /root, a folder that was closed to you a moment ago.

You can only use sudo if you are in the sudo group, which is why id listed 27(sudo) in lesson 5. That is the whole system: you work as yourself, and borrow the administrator's power for one command at a time.

Be careful what you install

How many Linux users does it take to change a light bulb?<br>
None. They just run <span class="command">apt install light</span> and wait for the dependencies.

🧪 Try it yourself

On your root practice machine:

1. Refresh the catalog. 2. Search for a package named exactly nano (a small friendly text editor you will use in lesson 10). 3. Install it, and use which to find it. 4. Remove it again, and check that which nano now prints nothing. (echo $? prints 1 when the last command found nothing.) 5. Bonus: as the ordinary ubuntu user, try the install without sudo and read the error. Then fix it the lesson's way.

The cheat sheet

← Lesson 5 · ↑ All lessons · Lesson 7: Processes: What Is Running and How to Stop It →