Installing software¶
Level 3 · Chapter 6 · ⏱️ ~55 min read · Prerequisites: Users, groups, and sudo, Filesystems, inodes, and links
On Linux you rarely download installers from websites. Software comes from signed repositories through a package manager, which tracks every file, resolves dependencies, and keeps everything updated together. This chapter takes apart the whole pipeline on Mint (dpkg, apt, repositories, signatures, PPAs, Update Manager) and then compares the alternatives: Flatpak, Snap, AppImage, building from source, and Python's pip.
Why it matters¶
Alex needs a newer version of a database client than Mint offers. A blog post says: add this PPA, then sudo apt install. Another says: download the tarball and sudo make install. A third says: sudo pip install the Python wrapper. Alex does all three over a month.
Six months later, a routine sudo apt full-upgrade wants to remove 40 packages. A Python tool for the desktop crashes on import because a system library was overwritten by pip. And nobody remembers which files make install scattered into /usr/local, so the old client keeps shadowing the new one.
Each shortcut was reasonable on its own. Together they broke the one thing that keeps a Linux system healthy: a single, consistent record of what's installed and where it came from. After this chapter, you'll know which installation method fits which situation, what each one trusts, and how to undo it.
Concepts¶
Packages and dependencies¶
A package is an archive containing a program's files plus metadata: its name, version, a description, which other packages it needs, and scripts to run during installation. On Debian, Ubuntu, and Mint, packages are .deb files.
Programs reuse code from shared libraries (you saw ls load libc.so.6 and libpcre2-8.so.0 in Memory). So packages declare dependencies: htop declares that it needs libc6 and libncursesw6. When you install htop, the package manager also installs any missing dependencies, and their dependencies, and so on.
Dependency relationships come in several strengths:
| Field | Meaning |
|---|---|
Depends |
Required. The package won't be configured without it |
Pre-Depends |
Required, and must be fully installed before this package is even unpacked |
Recommends |
Normally wanted. apt installs these by default; skip with --no-install-recommends |
Suggests |
Might be useful. Not installed by default |
Conflicts / Breaks |
Can't be installed together (or would break the other) |
Provides |
Satisfies a virtual name (several mail servers all provide mail-transport-agent) |
Because each library is installed once and shared, a security fix to libssl fixes every program that uses it in one update. That's the central advantage of the distribution package model, and the main thing the alternatives later in this chapter trade away.
dpkg and apt: two layers¶
There are two tools, stacked:
- dpkg is the low-level tool. It installs, removes, and queries individual
.debfiles that are already on your disk. It checks dependencies but doesn't fetch them; if one is missing, it refuses and stops. It keeps the database of what's installed in/var/lib/dpkg/. - apt is the high-level tool. It knows about repositories (servers full of packages), downloads what's needed, works out the full dependency tree, and then calls dpkg to do the actual installation in the right order.
flowchart LR
U["You:<br/>sudo apt install htop"] --> A["apt<br/>resolve deps,<br/>download, verify"]
A --> R["Repositories<br/>(HTTP mirrors)"]
A --> C["/var/cache/apt/archives<br/>*.deb files"]
C --> D["dpkg<br/>unpack, run scripts,<br/>record files"]
D --> DB["/var/lib/dpkg/<br/>status + info/*.list"]
D --> FS["Files in /usr, /etc, ..."]
The older commands apt-get and apt-cache do the same jobs as apt and are still preferred in scripts, because their output format is guaranteed stable. apt is the friendlier interactive front end, with progress bars and colour.
On Mint, apt is a wrapper
Type type -a apt and you'll see /usr/local/bin/apt listed before /usr/bin/apt. Mint ships a small Python wrapper that adds conveniences: it prefixes sudo for you on commands that need root, sends apt search to aptitude (so results look like p htop - interactive processes viewer, where p means not installed and i installed), and adds extra commands like apt contains FILE (= dpkg -S) and apt content PKG (= dpkg -L). apt help install shows what any command really runs. This handbook writes sudo apt ..., which works identically with or without the wrapper.
The apt pipeline: from repository to your disk¶
Sources: where packages come from¶
A repository (repo) is a web server with a standard directory layout of packages and index files. apt reads its list of repositories from:
/etc/apt/sources.list(the traditional single file; on Mint it's usually empty or just comments),- every
*.listand*.sourcesfile in/etc/apt/sources.list.d/.
There are two formats. The classic one-line format (.list files), which Mint uses for its official repositories in /etc/apt/sources.list.d/official-package-repositories.list:
deb http://packages.linuxmint.com zena main upstream import backport
deb http://archive.ubuntu.com/ubuntu noble main restricted universe multiverse
deb http://archive.ubuntu.com/ubuntu noble-updates main restricted universe multiverse
deb http://archive.ubuntu.com/ubuntu noble-backports main restricted universe multiverse
deb http://security.ubuntu.com/ubuntu/ noble-security main restricted universe multiverse
Each line is: type (deb for binary packages, deb-src for source code), URL, suite (the release name, zena for Mint 22.3 and noble for Ubuntu 24.04, optionally with a pocket like -updates or -security), and components (sections of the repo: Ubuntu's main is officially supported, universe is community-maintained, restricted and multiverse have licensing restrictions).
This tells you something important about Mint: most of your packages come from Ubuntu's servers. Mint's own repository adds Mint's tools, the Cinnamon desktop, and a few replaced packages on top.
The newer deb822 format (.sources files) is multi-line and more readable, and it's what Ubuntu 24.04 itself and many third-party vendors now use:
Types: deb
URIs: https://dl.google.com/linux/chrome-stable/deb/
Suites: stable
Components: main
Architectures: amd64
Signed-By: /usr/share/keyrings/google-chrome.gpg
Notice Signed-By. That ties this repository to one specific key, which matters for security (more below).
Mint's graphical Software Sources tool (in the menu, or mintsources) edits the official repository file for you, lets you switch to a faster mirror, and manages PPAs and keys.
apt update: download the indexes and verify them¶
sudo apt update doesn't upgrade anything. It refreshes apt's knowledge of what's available. For each repository it downloads:
InRelease: a small file listing every index file in the repository with its size and SHA-256 hash, signed with the repository's OpenPGP key. (Some repos use the older pairRelease+ a detachedRelease.gpgsignature instead.)- The
Packagesindex for each component and architecture: one entry per package with its version, dependencies, filename, size, and SHA-256 hash.
-----BEGIN PGP SIGNED MESSAGE-----
Hash: SHA512
Origin: Ubuntu
Label: Ubuntu
Suite: noble
Version: 24.04
Codename: noble
Date: Thu, 25 Apr 2024 15:10:33 UTC
Architectures: amd64 arm64 armhf i386 ppc64el riscv64 s390x
Components: main restricted universe multiverse
Description: Ubuntu Noble 24.04
These files are stored in /var/lib/apt/lists/, which is apt's package lists. All later searches and installs use this local copy, which is why you run apt update before installing: otherwise apt may try to download a version that's no longer on the server.
The chain of trust¶
Signatures and hashes form a chain from a key on your disk all the way to every file you install:
flowchart TD
K["Trusted key on disk<br/>/usr/share/keyrings/*.gpg"] -->|verifies signature of| I["InRelease"]
I -->|lists SHA-256 of| P["Packages index"]
P -->|lists SHA-256 of| D["htop_3.3.0-4build1_amd64.deb"]
D -->|contains| F["/usr/bin/htop"]
If anyone tampers with a .deb on a mirror, its hash won't match Packages. If they also change Packages, its hash won't match InRelease. If they change InRelease, its signature won't verify against your key. This is why apt can safely download over plain HTTP: integrity doesn't depend on the transport. (HTTPS would add privacy about what you download, not integrity.)
The keys live in keyrings:
/usr/share/keyrings/: installed by packages (Ubuntu'subuntu-archive-keyring.gpg, Mint'slinuxmint-keyring.gpg)./etc/apt/keyrings/: the recommended place for keys you add yourself for third-party repos./etc/apt/trusted.gpg.d/: the legacy location. A key here is trusted for every repository, not just its own.
The difference matters. A key referenced with Signed-By: can only vouch for that one repo. A key dropped in trusted.gpg.d could sign a fake libc6 in some other repo, and apt would accept it. The old apt-key add command did exactly that, which is why it's deprecated.
If verification fails, apt update warns loudly:
W: GPG error: https://example.com/apt stable InRelease: The following signatures couldn't be verified because the public key is not available: NO_PUBKEY 1234ABCD5678EF90
E: The repository 'https://example.com/apt stable InRelease' is not signed.
Never "fix" this by marking a repository [trusted=yes]. Get the right key from the vendor's official instructions.
Install: resolve, download, verify, unpack, configure¶
When you run sudo apt install htop:
- apt reads the package lists and computes everything that must change (new packages, upgrades, removals).
- It shows you the plan and asks for confirmation if it's more than the one package you named.
- It downloads the
.debfiles into the package cache,/var/cache/apt/archives/, and checks each one's hash. - It calls
dpkgfor each package, in dependency order. dpkg:- runs the package's preinst script (if any),
- unpacks the files into place,
- runs postinst (create users, enable services, update caches),
- records every installed path in
/var/lib/dpkg/info/PKG.listand the package's status in/var/lib/dpkg/status.
- Triggers run: shared hooks that several packages want to fire once at the end, like rebuilding the man-page index or the icon cache.
Maintainer scripts (preinst, postinst, prerm, postrm) run as root. Installing a package means trusting whoever built it with full control of your machine. Keep that in mind for the PPA section.
Configuration files¶
Files under /etc that a package marks as conffiles get special treatment. If you've edited one and an upgrade ships a new version, dpkg stops and asks whether to keep yours or take the maintainer's. When you remove a package, its conffiles stay behind, so reinstalling restores your configuration. Only purge deletes them.
Upgrade, full-upgrade, and automatic removals¶
| Command | What it does |
|---|---|
apt update |
Refresh package lists. Changes nothing installed |
apt upgrade |
Upgrade installed packages to the newest candidate versions. May install new dependencies, but never removes a package. Anything needing a removal is "kept back" |
apt full-upgrade |
Same, but allowed to remove packages when that's needed to resolve conflicts (apt-get dist-upgrade is the old name) |
apt autoremove |
Remove packages that were installed automatically as dependencies and are no longer needed by anything |
apt remembers why each package is installed: manually (you asked for it) or automatically (pulled in as a dependency). When nothing depends on an automatic package anymore, it becomes an autoremove candidate. apt-mark showmanual and apt-mark manual PKG inspect and change the marks. Kernels get special treatment: apt always keeps the running kernel and the newest one, and on Mint the easiest way to clean out older kernels is Update Manager's Kernel Manager (or its automatic kernel removal option).
On Ubuntu-based systems you may see The following upgrades have been deferred due to phasing. Ubuntu rolls some updates out gradually to a percentage of machines, so a few packages wait a day or two. That's normal; don't force them.
What goes where¶
Packages follow the Filesystem Hierarchy Standard you met in The filesystem layout:
| Path | Contents |
|---|---|
/usr/bin, /usr/sbin |
Programs |
/usr/lib, /usr/lib/x86_64-linux-gnu |
Libraries, plugins, and internal files |
/usr/share |
Architecture-independent data: icons, docs (/usr/share/doc/PKG), man pages, .desktop menu entries |
/etc |
System-wide configuration (conffiles) |
/var/lib/PKG |
Persistent state (databases, caches) |
/usr/lib/systemd/system |
systemd units shipped by packages |
/usr/local |
Not used by packages. Reserved for software you install by hand |
/opt |
Large self-contained third-party apps (Chrome lives in /opt/google/chrome) |
The split between /usr (owned by the package manager) and /usr/local (yours) is what lets dpkg and your hand-built software coexist without overwriting each other. /usr/local/bin comes before /usr/bin in PATH, so a locally built program shadows the packaged one with the same name. That's how Mint's apt wrapper takes priority over /usr/bin/apt.
PPAs: someone else's repository¶
A PPA (Personal Package Archive) is a repository hosted on Ubuntu's Launchpad service, where any individual or team can publish packages built for specific Ubuntu releases. PPAs are how you get newer versions than the distribution ships: a newer Python from deadsnakes, the latest Git from git-core, graphics drivers from graphics-drivers.
add-apt-repository ppa:OWNER/NAME (on Mint, provided by Mint's own mintsources package) creates a sources file in /etc/apt/sources.list.d/ and installs the PPA's signing key, scoped to that PPA. On Mint you can also manage PPAs in Software Sources → PPAs.
The trust implications are serious:
- Packages from a PPA run maintainer scripts as root. The PPA owner can do anything to your machine.
- A PPA can publish any package name, including
libc6oropenssh-server, with a higher version number, andapt upgradewill happily install it. - PPAs are usually maintained by one person. If they stop, you stop getting security fixes for those packages, and the stale versions may block future distribution upgrades.
- Mint upgrades between major versions can fail or behave oddly with PPAs enabled; Mint's upgrade tool disables them.
A good rule: use only PPAs run by the upstream project itself or by well-known teams, keep the number small, and remove a PPA once the distribution catches up.
Mint's Update Manager¶
Mint doesn't expect you to live in a terminal for updates. Update Manager (mintupdate, the shield icon in the panel) is the recommended way to keep the system current. It:
- runs the equivalent of
apt updatein the background and shows available updates, grouped by source package, with security updates and kernel updates labelled; - lets you ignore specific updates (blacklist) and view changelogs;
- updates Flatpaks and Cinnamon spices (applets, themes) in the same place;
- includes a Kernel Manager to install other kernel series or remove old kernels safely;
- offers automatic updates and automatic removal of obsolete kernels (Edit → Preferences → Automation), which install via systemd timers named
mintupdate-automation-*.timer; - reminds you to set up Timeshift, Mint's system snapshot tool, so a bad update can be rolled back.
There's also a command-line interface:
security openssl 3.0.13-0ubuntu3.6
package mesa 25.2.8-0ubuntu0.24.04.3
package dnsmasq 2.91-0ubuntu0.24.04.1
kernel linux-hwe-6.14 6.14.0-37.37~24.04.1
Each line is the update type, the source package (one source package can build several binary packages, like mesa building libegl-mesa0 and friends), and the new version. mintupdate-cli upgrade installs them; -s limits either command to security updates, -k to kernel updates, -r refreshes the cache first, and -d makes upgrade a dry run.
Beyond apt: Snap, Flatpak, AppImage¶
Distribution packages have a downside: an app's version is frozen to what the distribution ships for that release. Mint 22.3 is built on Ubuntu 24.04, so its LibreOffice or GIMP may be a year or more behind. Three cross-distribution formats solve this by bundling an application with its dependencies, so one build runs on any distribution.
Snap, and why Mint blocks it¶
Snap is Canonical's format. A snap is a compressed squashfs image, mounted read-only on a loop device (you saw /snap/core22/... mounts in the previous chapter). The snapd daemon installs, mounts, and automatically refreshes snaps, and confines them using AppArmor.
Ubuntu uses snaps heavily: Firefox and Chromium on Ubuntu are snaps. In 2019, Ubuntu turned its chromium-browser .deb into an empty transitional package whose installation script quietly installed snapd and the Chromium snap. Mint objected, and since Mint 20 it blocks snapd from being installed through apt with a file in /etc/apt/preferences.d/:
# To prevent repository packages from triggering the installation of Snap,
# this file forbids snapd from being installed by APT.
# For more information: https://linuxmint-user-guide.readthedocs.io/en/latest/snap.html
Package: snapd
Pin: release a=*
Pin-Priority: -10
A negative pin priority means "never install". Mint's reasons:
- Installing via apt shouldn't silently connect you to a different store. A
.debthat installs a snap bypasses the user's choice of package source. - The Snap Store is centralized. Only Canonical's server can serve snaps to
snapd, and its server software isn't open source. You can't run your own store or mirror the way you can with apt repositories or Flatpak remotes. - Automatic refreshes happen in the background on Canonical's schedule (they can be delayed but not fully disabled), which takes control away from the user and from Update Manager.
Mint packages Chromium as a regular .deb instead. If you really want snaps, you can remove the pin file and install snapd; it works fine. It's a policy default, not a technical limitation.
Flatpak: Mint's default for third-party apps¶
Flatpak is a community-driven format (originally from Red Hat/GNOME developers). It's Mint's preferred way to get up-to-date desktop apps, built into Software Manager:
- Apps come from remotes; the main one is Flathub, which Mint enables out of the box. Anyone can run their own remote.
- Apps depend on shared runtimes (
org.freedesktop.Platform,org.gnome.Platform,org.kde.Platform), versioned bundles of common libraries. Ten GNOME apps share one GNOME runtime rather than each bundling its own. - Apps run in a sandbox built with
bubblewrapand Linux namespaces. They see only the files and devices their permissions allow, and they reach the rest of the desktop through portals (for example, a file-chooser dialog that hands the app only the file you picked). - Storage is deduplicated (OSTree), and updates download only changed files.
- Installations can be system-wide (
/var/lib/flatpak) or per-user (~/.local/share/flatpak).
Flathub apps are often packaged by volunteers rather than the app's developers. Recent versions of Mint's Software Manager distinguish verified apps (published by the upstream developer) and hide unverified ones by default; you can enable them in its preferences. Many apps also request broad permissions, such as access to your whole home directory, which weakens the sandbox. flatpak info --show-permissions APP shows what an app gets, and the Flatseal app lets you change it.
AppImage: one file, no installation¶
An AppImage is a single executable file containing an app and its libraries. Download it, make it executable, run it. Nothing is installed and nothing needs root. To remove it, delete the file.
The trade-offs: no automatic updates (unless the app updates itself), no sandbox, no menu entry unless you add one, and you're trusting whatever website you downloaded it from, with no signature checking by default. Most AppImages need the old FUSE 2 library, packaged as libfuse2t64 on Mint 22.
Building from source¶
Sometimes a program isn't packaged anywhere. Classic C projects are built with the autotools routine:
./configure # check your system for compilers and libraries; write a Makefile
make # compile
sudo make install # copy the results into place (default prefix: /usr/local)
./configure defaults to --prefix=/usr/local, so the result lands in /usr/local/bin, /usr/local/lib, and /usr/local/share, away from the package manager's /usr. Many modern projects use other build systems (CMake, Meson, Cargo, Go), but the ideas are the same; Building software goes deeper into compiling and linking.
Why to avoid sudo make install when you have a choice:
- dpkg doesn't know about it. There's no record of which files were installed, so there's often no clean uninstall (only if the project happens to provide
make uninstall, and only from the same build tree). - No updates. Security fixes never arrive unless you rebuild by hand.
- Shadowing.
/usr/local/bincomes first inPATH, so a forgotten old build silently wins over a newer packaged version. - Build dependencies. You install
-devpackages and compilers you may not otherwise need.
Better options, in order: a package from your distribution; an official vendor repository or Flatpak; installing into your home directory without root (./configure --prefix="$HOME/.local", then make install without sudo); or checkinstall, which runs make install, records the files, and builds a .deb so dpkg can track and remove it. (checkinstall is in Ubuntu's universe repository but is old and unmaintained; it works for simple projects.)
Python packages: pip, venv, and PEP 668¶
Python has its own package manager, pip, which installs from PyPI (the Python Package Index). The trouble starts when pip and apt both manage the same directory. Mint's own tools (Update Manager, Software Sources, Software Manager, and many others) are written in Python and depend on specific versions of packages installed by apt into /usr/lib/python3/dist-packages. A sudo pip install that upgrades one of those can break system tools in ways that are hard to trace.
To stop this, Python adopted PEP 668: a distribution can mark its system Python as externally managed by placing a file named EXTERNALLY-MANAGED in the standard library directory. Ubuntu 24.04 and Mint 22 do:
error: externally-managed-environment
× This environment is externally managed
╰─> To install Python packages system-wide, try apt install
python3-xyz, where xyz is the package you are trying to
install.
If you wish to install a non-Debian-packaged Python package,
create a virtual environment using python3 -m venv path/to/venv.
Then use path/to/venv/bin/python and path/to/venv/bin/pip. Make
sure you have python3-full installed.
If you wish to install a non-Debian packaged Python application,
it may be easiest to use pipx install xyz, which will manage a
virtual environment for you. Make sure you have pipx installed.
See /usr/share/doc/python3.12/README.venv for more information.
note: If you believe this is a mistake, please contact your Python installation or OS distribution provider. You can override this, at the risk of breaking your Python installation or OS, by passing --break-system-packages.
hint: See PEP 668 for the detailed specification.
The message lists the three right answers:
- System-wide library that the distribution packages:
sudo apt install python3-requests. - Libraries for your own project: a virtual environment (venv), a self-contained directory with its own
pythonandpipand its ownsite-packages. Nothing outside it is touched. - A Python command-line application (like
black,httpie,poetry):pipx, which creates a hidden venv per application and puts the command on yourPATHin~/.local/bin.
And it names the wrong answer, --break-system-packages, in a way that makes the risk clear.
Common mistake
sudo pip install .... Even before PEP 668 this was the most common way to break a Debian or Ubuntu system's Python: it installs as root into system directories that apt manages. Never combine sudo with pip.
Data engineers will also meet conda and uv. Both manage their own Python installations and environments entirely separate from the system Python, which is another valid way to avoid the conflict.
Commands and examples¶
Searching and inspecting¶
(On Mint, the apt wrapper hands search to aptitude, so you'll see p htop - interactive processes viewer instead. /usr/bin/apt search gives the upstream format.)
Details of a package, installed or not:
Package: htop
Version: 3.3.0-4build1
Priority: optional
Section: utils
Origin: Ubuntu
Maintainer: Ubuntu Developers <ubuntu-devel-discuss@lists.ubuntu.com>
Installed-Size: 434 kB
Depends: libc6 (>= 2.38), libncursesw6 (>= 6), libnl-3-200 (>= 3.2.7), libnl-genl-3-200 (>= 3.2.7), libtinfo6 (>= 6)
Suggests: lm-sensors, lsof, strace
Homepage: https://htop.dev/
Download-Size: 171 kB
APT-Sources: http://archive.ubuntu.com/ubuntu noble/main amd64 Packages
Description: interactive processes viewer
Htop is an ncursed-based process viewer similar to top, but it
allows one to scroll the list vertically and horizontally to see
all processes and their full command lines.
APT-Sources tells you which repository the candidate comes from.
Which version will be installed, and from where:
coreutils:
Installed: 9.4-3ubuntu6.3
Candidate: 9.4-3ubuntu6.3
Version table:
*** 9.4-3ubuntu6.3 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
9.4-3ubuntu6 500
500 http://archive.ubuntu.com/ubuntu noble/main amd64 Packages
Installedis what you have;Candidateis whatapt install/upgradewould pick.- Each version lists the repositories offering it with a priority: 500 is the default for normal repos, 100 is the "currently installed" pseudo-repo. Higher priority wins; among equals, the higher version wins.
***marks the installed version.
apt policy with no package name lists every repository and its priority. On Mint you'll see Mint's own repositories pinned at 700 by /etc/apt/preferences.d/official-package-repositories.pref, so Mint's versions of a package beat Ubuntu's.
Dependencies both ways:
htop
Depends: libc6
Depends: libncursesw6
Depends: libnl-3-200
Depends: libnl-genl-3-200
Depends: libtinfo6
Suggests: lm-sensors
Suggests: lsof
Suggests: strace
libpcre2-8-0
Reverse Depends:
wget
libvte-2.91-0
libselinux1
rdepends (reverse dependencies) answers "what would break if this were removed?".
Updating and upgrading¶
Hit:1 http://packages.linuxmint.com zena InRelease
Hit:2 http://archive.ubuntu.com/ubuntu noble InRelease
Get:3 http://archive.ubuntu.com/ubuntu noble-updates InRelease [126 kB]
Get:4 http://security.ubuntu.com/ubuntu noble-security InRelease [126 kB]
Hit:5 http://archive.ubuntu.com/ubuntu noble-backports InRelease
Get:6 http://archive.ubuntu.com/ubuntu noble-updates/main amd64 Packages [1,402 kB]
Fetched 1,780 kB in 2s (891 kB/s)
Reading package lists... Done
Building dependency tree... Done
Reading state information... Done
12 packages can be upgraded. Run 'apt list --upgradable' to see them.
Hit means the index hasn't changed since last time; Get means a newer one was downloaded. Each InRelease was signature-checked; a failure would print a W: or E: line.
Listing... Done
dnsmasq-base/noble-updates 2.91-0ubuntu0.24.04.1 amd64 [upgradable from: 2.90-2ubuntu0.4]
libegl-mesa0/noble-updates 25.2.8-0ubuntu0.24.04.3 amd64 [upgradable from: 25.2.8-0ubuntu0.24.04.2]
...
The following packages will be upgraded:
dnsmasq-base libegl-mesa0 ...
12 upgraded, 0 newly installed, 0 to remove and 0 not upgraded.
Need to get 18.4 MB of archives.
After this operation, 41.0 kB of additional disk space will be used.
Do you want to continue? [Y/n]
Read the summary line every time: upgraded, newly installed, to remove, not upgraded. A surprising "to remove" count is your cue to stop and look. sudo apt full-upgrade is the same with removals allowed. On Mint, Update Manager does all of this for you; the commands are what it runs underneath.
Installing and removing¶
Reading package lists... Done
Building dependency tree... Done
Reading state information... Done
Suggested packages:
lm-sensors
The following NEW packages will be installed:
htop
0 upgraded, 1 newly installed, 0 to remove and 12 not upgraded.
Need to get 171 kB of archives.
After this operation, 434 kB of additional disk space will be used.
Get:1 http://archive.ubuntu.com/ubuntu noble/main amd64 htop amd64 3.3.0-4build1 [171 kB]
Fetched 171 kB in 1s (215 kB/s)
Selecting previously unselected package htop.
(Reading database ... 412345 files and directories currently installed.)
Preparing to unpack .../htop_3.3.0-4build1_amd64.deb ...
Unpacking htop (3.3.0-4build1) ...
Setting up htop (3.3.0-4build1) ...
Processing triggers for desktop-file-utils (0.27-2build1) ...
Processing triggers for hicolor-icon-theme (0.17-2) ...
Processing triggers for man-db (2.12.0-4build2) ...
You can see the pipeline from the Concepts section: plan, download into the cache, then dpkg's "Unpacking" and "Setting up" (postinst), then triggers. lsof and strace aren't listed as suggestions because they're already installed.
Removing:
sudo apt remove htop # remove files, keep conffiles in /etc
sudo apt purge htop # remove files AND conffiles
sudo apt autoremove # remove orphaned automatic dependencies
dpkg -l shows the difference between removed and purged:
Desired=Unknown/Install/Remove/Purge/Hold
| Status=Not/Inst/Conf-files/Unpacked/halF-conf/Half-inst/trig-aWait/Trig-pend
|/ Err?=(none)/Reinst-required (Status,Err: uppercase=bad)
||/ Name Version Architecture Description
+++-==============-===============-============-=================================
ii coreutils 9.4-3ubuntu6.3 amd64 GNU core utilities
ii htop 3.3.0-4build1 amd64 interactive processes viewer
rc nginx 1.24.0-2ubuntu7 amd64 small, powerful, scalable web/proxy server
The two letters are desired state and actual state: ii = wanted installed, is installed. rc = removed, but config files remain (a purge would clear it). Find all leftover configs with dpkg -l | grep '^rc'.
Common mistake
Confirming a removal without reading the list. sudo apt remove python3 or removing a library that the desktop depends on will propose removing dozens of packages, including mint-meta-cinnamon and the desktop itself. apt shows the full list and asks Do you want to continue? [Y/n]. If the list contains anything you didn't expect, answer n. The same goes for autoremove right after uninstalling a big application.
Installing a downloaded .deb:
The ./ matters: it tells apt this is a file path, not a package name. Unlike sudo dpkg -i file.deb, apt also downloads and installs the .deb's dependencies.
Querying dpkg: which package owns what¶
dpkg -S /usr/bin/ls # which package installed this file?
dpkg -L coreutils | head -6 # which files did this package install?
dpkg -s coreutils | head -6 # status and metadata of an installed package
coreutils: /usr/bin/ls
/.
/usr
/usr/bin
/usr/bin/[
/usr/bin/arch
/usr/bin/b2sum
Package: coreutils
Essential: yes
Status: install ok installed
Priority: required
Section: utils
Installed-Size: 6944
Essential: yes means the system can't function without it, and apt will make you type a full confirmation sentence before removing it. These queries read dpkg's database directly:
coreutils.list is the file list dpkg -L prints, and md5sums lets dpkg --verify coreutils detect modified files. Packages with maintainer scripts also have .postinst, .prerm, and so on in this directory.
dpkg -S on a file that no package owns prints dpkg-query: no path found matching pattern. That's a quick way to spot files that came from make install or pip.
Cache and lists housekeeping¶
du -sh /var/cache/apt/archives /var/lib/apt/lists
sudo apt clean # delete all cached .deb files
sudo apt autoclean # delete only cached .debs that can no longer be downloaded
The cache is only for re-installing without downloading; deleting it is safe.
PPAs in practice¶
⚠️ VM only
Practise adding and removing PPAs in your VM. A PPA gets root-level trust on your machine and can replace core system packages.
git:
Installed: 1:2.43.0-1ubuntu7.3
Candidate: 1:2.51.0-0ppa1~ubuntu24.04.1
Version table:
1:2.51.0-0ppa1~ubuntu24.04.1 500
500 https://ppa.launchpadcontent.net/git-core/ppa/ubuntu noble/main amd64 Packages
*** 1:2.43.0-1ubuntu7.3 500
500 http://archive.ubuntu.com/ubuntu noble-updates/main amd64 Packages
100 /var/lib/dpkg/status
The PPA offers a newer version at the same priority, so it becomes the candidate. Look at what was added:
To remove it cleanly and go back to the distribution's version, use ppa-purge (a small package that downgrades everything from the PPA), or remove the PPA in Software Sources and then reinstall the distribution version:
Note that Mint's add-apt-repository uses Ubuntu's codename (noble), not Mint's (zena), because PPAs are built for Ubuntu releases.
Flatpak¶
flatpak remotes
flatpak search obsidian
flatpak install flathub md.obsidian.Obsidian
flatpak list --app
Name Options
flathub system
Name Description Application ID Version Branch Remotes
Obsidian Markdown-based knowledge base md.obsidian.Obsidian 1.13.7 stable flathub
...
Name Application ID Version Branch Installation
Obsidian md.obsidian.Obsidian 1.13.7 stable system
Apps are identified by reverse-DNS application IDs. Other everyday commands:
flatpak run md.obsidian.Obsidian # run from the terminal
flatpak update # update all apps and runtimes
flatpak info --show-permissions md.obsidian.Obsidian
flatpak uninstall md.obsidian.Obsidian
flatpak uninstall --unused # remove runtimes nothing uses anymore
[Context]
shared=network;ipc;
sockets=wayland;pulseaudio;fallback-x11;ssh-auth;
devices=dri;
filesystems=home;/media;/mnt;/run/media;
That app can reach the network and your entire home directory, so its sandbox protects the rest of the system but not your files. --user on install keeps everything in your home directory without root.
AppImage¶
If it fails with dlopen(): error loading libfuse.so.2, install the compatibility library: sudo apt install libfuse2t64. Verify the download against the checksum or signature the project publishes before running it.
Comparing the formats¶
Source: Ubuntu and Mint repositories, plus vendor repos and PPAs.
Strengths: Shared libraries, so security fixes land everywhere at once; tight integration; small downloads; the default for everything system-level (drivers, servers, command-line tools, libraries).
Weaknesses: Versions frozen to the release; third-party repos and PPAs get root-level trust.
Updates: Update Manager / apt upgrade.
Source: Flathub (enabled on Mint), or any other remote.
Strengths: Current versions of desktop apps; sandboxed with portals; shared runtimes; works on any distro; can install per-user without root; integrated into Mint's Software Manager and Update Manager.
Weaknesses: Larger disk use (runtimes); sandbox only as strong as the requested permissions; themes and system integration sometimes imperfect; not meant for command-line tools or system services.
Updates: Update Manager / flatpak update.
Source: Canonical's Snap Store only.
Strengths: Current versions; works for desktop apps, command-line tools, and services; confined with AppArmor; default on Ubuntu.
Weaknesses: Single proprietary store; background auto-refresh; loop mounts clutter lsblk and df; slower first start. Blocked on Mint by default via an apt pin.
Updates: Automatic (snap refresh).
Source: The developer's website or GitHub releases.
Strengths: One file, no install, no root; easy to keep several versions; easy to delete.
Weaknesses: No sandbox, no automatic updates, no signature checks by default, no menu integration without extra tools; needs libfuse2t64.
Updates: Manual (download the new file).
Source: The project's source code.
Strengths: Latest code; custom build options; works when nothing else exists.
Weaknesses: Untracked by dpkg; no updates; files scattered in /usr/local; needs compilers and -dev packages.
Updates: Rebuild by hand.
A sensible default on Mint: apt for system tools and anything in the repositories, Flatpak for desktop apps you want newer than the repos, venv/pipx for Python, and source builds only when there's no other way.
Building from source, carefully¶
⚠️ VM only
sudo make install writes untracked files into system directories. Try it in your VM, or install into your home directory without sudo as shown below.
A safe pattern that never needs root:
sudo apt install build-essential # gcc, make, and friends (once)
cd ~/src
tar xf jq-1.7.1.tar.gz && cd jq-1.7.1
./configure --prefix="$HOME/.local" --with-oniguruma=builtin
make -j"$(nproc)"
make install
command -v jq
-j"$(nproc)" runs one compile job per CPU. Mint's default ~/.profile adds ~/.local/bin to PATH if the directory exists when you log in, so log out and back in after creating it. To uninstall, delete the files the build installed (many projects support make uninstall from the same build directory).
If you must install system-wide, checkinstall (in the VM) gives you an uninstallable package:
sudo apt install checkinstall
./configure && make
sudo checkinstall --pkgname=jq-local --pkgversion=1.7.1 --default
dpkg -L jq-local | head -3
sudo apt remove jq-local
Python the right way¶
cd ~/projects/etl
python3 -m venv .venv
source .venv/bin/activate
pip install pandas pyarrow
python -c "import pandas, sys; print(pandas.__version__, sys.prefix)"
deactivate
sys.prefix confirms the interpreter is running from the venv. Everything pip installed lives in .venv/lib/python3.12/site-packages; delete .venv and it's all gone. If python3 -m venv complains that ensurepip is not available, run sudo apt install python3-venv once.
For command-line Python tools:
pipx gave httpie its own private venv under ~/.local/share/pipx/venvs/ and linked its commands into ~/.local/bin.
Exercises¶
Exercise 1: Trace a command back to its package (easy)¶
Find which package provides /usr/bin/top, list the other programs that package installed into /usr/bin, and find which repository and version it came from.
Solution
procps: /usr/bin/top
/usr/bin/free
/usr/bin/kill
/usr/bin/pgrep
/usr/bin/pidwait
/usr/bin/pmap
/usr/bin/ps
/usr/bin/pwdx
/usr/bin/skill
/usr/bin/slabtop
/usr/bin/tload
/usr/bin/top
/usr/bin/uptime
/usr/bin/vmstat
/usr/bin/w
/usr/bin/watch
/usr/bin/pkill
/usr/bin/snice
procps:
Installed: 2:4.0.4-4ubuntu3.2
Candidate: 2:4.0.4-4ubuntu3.2
Version table:
*** 2:4.0.4-4ubuntu3.2 500
500 http://archive.ubuntu.com/ubuntu noble-updates/main amd64 Packages
...
procps is the package behind most of the process and memory tools from earlier chapters, all of which read /proc, hence the name. It comes from Ubuntu's noble-updates pocket, not from Mint's repo. (Exact version numbers will differ.) On Mint, apt contains /usr/bin/top and apt content procps are wrapper shortcuts for the same dpkg queries.
Exercise 2: Read your sources and keys (easy)¶
List every repository your system uses. For each third-party one, find the key it's tied to. Are any keys in the legacy /etc/apt/trusted.gpg.d/ location?
Solution
ls /etc/apt/sources.list.d/
grep -rhE '^(deb|URIs|Signed-By)' /etc/apt/sources.list /etc/apt/sources.list.d/ 2>/dev/null
ls /etc/apt/keyrings/ /usr/share/keyrings/ /etc/apt/trusted.gpg.d/ 2>/dev/null
apt policy | grep -E '^ *[0-9]+ ' | sort -u
A fresh Mint 22.3 has only official-package-repositories.list (Mint + Ubuntu) and Ubuntu's and Mint's keys in /usr/share/keyrings. Each third-party .sources file should have a Signed-By: line pointing at its own key; a .list file may carry the same thing inline as deb [signed-by=/etc/apt/keyrings/vendor.gpg] https://.... Keys in /etc/apt/trusted.gpg.d/ are trusted for every repo, so if a third-party key sits there, it's worth moving to /etc/apt/keyrings/ and referencing it with signed-by (in your VM first). The apt policy priorities show Mint's repos at 700 and everything else at 500.
Exercise 3: Remove vs purge (medium)¶
⚠️ VM only
This installs and removes packages; do it in your VM.
Install a package that ships configuration files in /etc, such as nginx, then remove it. Show the dpkg -l status and which files remain. Then purge it and show the difference.
Solution
sudo apt install nginx
dpkg -l nginx | tail -1
sudo apt remove nginx
dpkg -l nginx | tail -1
ls /etc/nginx
sudo apt purge nginx
dpkg -l nginx 2>&1 | tail -1
ls /etc/nginx 2>&1
sudo apt autoremove
ii nginx 1.24.0-2ubuntu7.5 amd64 small, powerful, scalable web/proxy server
rc nginx 1.24.0-2ubuntu7.5 amd64 small, powerful, scalable web/proxy server
conf.d fastcgi.conf ... nginx.conf sites-available sites-enabled ...
dpkg-query: no packages found matching nginx
ls: cannot access '/etc/nginx': No such file or directory
After remove, the state is rc and /etc/nginx survives, so a reinstall would bring back your configuration. After purge, dpkg forgets the package entirely and the conffiles are gone. autoremove then offers to remove nginx-common and other automatic dependencies that nothing needs anymore. (On Ubuntu 24.04 the nginx package is split into nginx and nginx-common; most conffiles belong to nginx-common, so purge that too if /etc/nginx remains.)
Exercise 4: Watch PEP 668 protect you (medium)¶
Show that pip install is blocked for the system Python, find the EXTERNALLY-MANAGED marker file, then create a venv in ~/scratch/pep668, install requests there, and prove that the system Python can't import it while the venv's Python can.
Solution
pip install requests 2>&1 | head -2
python3 -c "import sysconfig; print(sysconfig.get_path('stdlib'))"
ls /usr/lib/python3.12/EXTERNALLY-MANAGED
mkdir -p ~/scratch/pep668 && cd ~/scratch/pep668
python3 -m venv .venv
.venv/bin/pip install --quiet requests
.venv/bin/python -c "import requests; print('venv:', requests.__version__)"
python3 -c "import requests" 2>&1 | tail -1
error: externally-managed-environment
/usr/lib/python3.12
/usr/lib/python3.12/EXTERNALLY-MANAGED
venv: 2.32.5
Calling .venv/bin/python directly is equivalent to activating the venv. The last command's result depends on your system: if Mint already has the python3-requests deb installed, the system Python imports that copy (an older version from apt), which shows the two are separate; if not, you'll see ModuleNotFoundError: No module named 'requests'. Either way the venv's copy never touched the system directories.
Exercise 5: Same app, three formats (hard)¶
⚠️ VM only
This adds a package source and installs software in several formats. Use your VM.
In the VM, install one application three ways: from apt, as a Flatpak, and (if the project offers one) as an AppImage. A good candidate is vlc or gimp. For each, record the version, where its files live, disk space used, and how it would be updated. Then remove all three cleanly.
Solution
# apt
sudo apt install gimp
apt policy gimp | head -3
dpkg -L gimp | grep -c . # number of files
dpkg-query -W -f='${Installed-Size} KiB\n' gimp
# Flatpak
flatpak install -y flathub org.gimp.GIMP
flatpak info org.gimp.GIMP | grep -E 'Version|Installed|Runtime'
du -sh /var/lib/flatpak/app/org.gimp.GIMP
# AppImage (download from the project's site into ~/Applications)
chmod +x ~/Applications/GIMP-*.AppImage
ls -lh ~/Applications/GIMP-*.AppImage
Typical findings: the apt version is the oldest (frozen at what Ubuntu 24.04 ships), installed across /usr/bin, /usr/lib, and /usr/share with dozens of shared-library dependencies, and updated by Update Manager. The Flatpak is newer, lives under /var/lib/flatpak/app/, depends on a runtime that may be several hundred MB (shared with other apps), and updates with flatpak update or Update Manager. The AppImage is a single file of a few hundred MB in your home directory, updated only by downloading a new file.
Cleanup:
Check yourself¶
-
What's the division of labour between dpkg and apt?
Answer
dpkg installs, removes, and queries individual
.debfiles on disk and keeps the installed-package database. apt reads repository indexes, resolves dependencies, downloads and verifies packages, then calls dpkg to install them in order. -
What does
apt updateactually do, and why must it run beforeapt install?Answer
It downloads each repository's signed
InReleaseandPackagesindexes into/var/lib/apt/lists/, verifying signatures. It installs nothing. Without fresh lists, apt may try to fetch versions that no longer exist on the mirror, or miss newer ones. -
Describe the chain of trust that protects a
.debdownloaded over plain HTTP.Answer
A key in a local keyring verifies the signature on
InRelease;InReleasecontains the SHA-256 of thePackagesindex;Packagescontains the SHA-256 of each.deb. Tampering anywhere breaks a hash or the signature. HTTPS isn't needed for integrity. -
What's the difference between
apt upgradeandapt full-upgrade?Answer
upgradenever removes installed packages (it holds back upgrades that would need removals).full-upgrademay remove packages to resolve changed dependencies. -
What's the difference between
removeandpurge, and how do you spot leftovers?Answer
removedeletes the package's files but keeps its conffiles in/etc;purgedeletes those too.dpkg -l | grep '^rc'lists removed-but-not-purged packages. -
Why is adding a PPA a trust decision, not just a convenience?
Answer
PPA packages run maintainer scripts as root and can replace any package on the system, including core libraries, with a higher version. You're trusting the PPA owner with full control of your machine and with keeping those packages patched.
-
Why does Mint block snapd by default, and how is Flatpak different?
Answer
Mint objected to apt packages silently installing snaps (Ubuntu's Chromium transition), to the Snap Store being a single, proprietary, Canonical-controlled backend, and to forced background auto-refreshes. Flatpak is decentralized (anyone can host a remote; Flathub is just the main one), integrated into Mint's Software Manager and Update Manager, and updates when you choose.
-
pip installfails withexternally-managed-environment. What are the three correct alternatives?Answer
Install the distribution's package (
sudo apt install python3-xyz); create a virtual environment for your project (python3 -m venv .venv); or usepipxfor a standalone Python application. Notsudo pip, and not--break-system-packages.
Key takeaways¶
- Packages bundle files plus metadata and dependencies. dpkg handles single
.debfiles and the database; apt handles repositories, dependency resolution, and downloads. - Repositories are listed in
/etc/apt/sources.list.d/(.listor deb822.sources). A signedInReleasefile and hashes form a chain of trust;Signed-Byscopes each key to one repo. updaterefreshes lists;upgradenever removes;full-upgrademay;removekeeps conffiles,purgedoesn't;autoremovecleans orphaned dependencies. Always read the summary before saying yes.dpkg -S,dpkg -L,dpkg -l, andapt policyanswer "who owns this file", "what did this install", "what state is it in", and "where will it come from".- PPAs and third-party repos get root-level trust; keep them few. On Mint, Update Manager is the normal way to update.
- Flatpak (Mint's default for newer desktop apps), Snap (blocked by default on Mint), and AppImage bundle dependencies for cross-distro apps, each with different trade-offs.
- Avoid
sudo make installandsudo pip; use$HOME/.local, checkinstall, venvs, or pipx.
Next¶
You've now seen every layer of a running Linux system. Prove it to yourself with the Level 3 capstone: explain everything from power-on to the login screen, and from typing ls to seeing its output.