📦 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
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
- URIs is the address of the repository. The second block is the separate security-updates server.
- Suites: noble noble-updates noble-backports are the release itself (noble is the codename of Ubuntu 24.04), its bug-fix updates, and a few newer versions of some programs. The security block adds noble-security.
- Components is the kind of software: main is software Ubuntu officially supports; universe is community-maintained; restricted is software that is not under a fully free licence, such as some drivers; and multiverse is software with no support from Ubuntu at all. (The comments in the file itself explain each one.)
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
- apt search looks for packages. We added --names-only '^tree$' so it matches only a package whose whole name is exactly tree; without that it also searches every description and prints a very long list. (The ^ and $ mean "start of the name" and "end of the name".)
- apt-cache policy tree shows the status: Installed: (none) and the Candidate, the version that would be installed, and which repository it comes from.
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
- apt install -y tree downloaded one small package (47.4 kB) and installed it. The -y means "yes": normally apt stops and asks Do you want to continue? [Y/n] before it does anything, and -y answers that for you. Read the summary lines before you say yes, especially "will be installed", "will be REMOVED" and the sizes.
- which tree prints where the new program lives: /usr/bin/tree.
- tree -L 1 /usr is the program itself. It draws folders as a tree, and -L 1 limits it to one level. It is a nice way to see a folder at a glance.
- dpkg -L tree lists every file the package put on your machine: the program, its documentation and its manual page. dpkg is the lower-level tool that apt uses underneath.
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:
- command -v less curl confirms where both landed, and less is the pager you have been waiting for. Open it with less /etc/passwd: Space moves down a page, b goes back, /word searches, and q quits. (It takes over the whole screen, so it does not show well in a written lesson. Try it on your own practice machine.)
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:
- ls /root failed: Permission denied, as in lesson 5.
- 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?".
- 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.
- 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.
- The command then ran with full administrator rights, and tree was installed.
- 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
- Start with Ubuntu's own repositories, as in this lesson. They are signed and reviewed.
- Be suspicious of any website that tells you to paste a command that downloads a script and runs it as the administrator (you will see commands that end in | sudo bash). That hands a stranger full control of your machine. Read what it does first, or find a package instead.
- Third-party repositories and "PPAs" can be fine, but each one is a person or company you are choosing to trust. Add as few as you can.
- Ubuntu also has a second packaging system called snap, which you will see on a desktop. It is outside this lesson (from the documentation, not run here).
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
- sudo apt update refresh the catalog (installs nothing). Do it before installing.
- apt search --names-only '^NAME$' find a package. apt-cache policy NAME its version and source.
- sudo apt install NAME install. -y answers yes for you. sudo apt remove NAME removes it. purge also removes its settings.
- sudo apt upgrade installs the waiting updates. apt list --upgradable shows what is waiting.
- dpkg -L NAME lists the files a package installed. which NAME shows where a program is.
- sudo !! re-runs the last command with sudo. sudo asks for your own password, shows nothing as you type, and remembers you for about 15 minutes.
- On the root practice machine drop the sudo. Never paste commands that download and run scripts as the administrator.
← Lesson 5 · ↑ All lessons · Lesson 7: Processes: What Is Running and How to Stop It →