Packages#

Packages are the standard unit of software installation on Linux. Every major distribution family ships a package manager that does the same five things. Install, upgrade, query, remove, and resolve dependencies against signed repositories. The syntax differs across apt, dnf, pacman, zypper, and apk; the architecture is identical.

For the operator, the package manager is the first place to read the box. The installed-package database answers what is on this host. The history log answers what changed and when. The repository configuration answers what could land here next. Each read is faster than reconstructing the same picture from the filesystem.

The same manager is also the operator’s supply chain on every authorized engagement. A third-party repo, a sideloaded .deb or .rpm, a vendor install script running with package-manager trust, all land code into the system with the same authority as the distro’s own packages. The GPG signing chain is the gate. Read where the keys live, how the manager verifies a fetched archive, and which third-party sources have been added before trusting the state of the box.

Quick orientation:

Question

Command

What manager is here?

command -v apt dnf pacman apk zypper

What distro family?

cat /etc/os-release

Is package X installed?

dpkg -l X / rpm -q X / pacman -Q X / apk info -e X

What owns a file?

dpkg -S F / rpm -qf F / pacman -Qo F

Install history?

/var/log/dpkg.log, dnf history list, /var/log/pacman.log

Every package manager does the same five things; the syntax differs, the architecture doesn’t.

        sequenceDiagram
  participant O as operator
  participant M as manager
  participant R as repository
  participant C as local cache
  participant D as package db
  O->>M: install PKG
  M->>R: fetch index
  R-->>M: package list + metadata
  M->>M: resolve dep graph
  M->>R: download archives
  R-->>C: .deb / .rpm / .pkg.tar.zst / .apk
  M->>M: verify GPG signatures
  M->>D: unpack + run pre/post scripts
  M->>D: update package database
  D-->>O: install complete
    

Stage

What happens

Repository

A signed source of packages (URL + GPG key). Configured in /etc/<mgr>/...; the manager downloads an index listing what’s available.

Resolve

Compute the full dependency graph for a requested package: what else must be installed, upgraded, or removed.

Fetch

Download the resolved set as .deb / .rpm / .pkg.tar.zst / .apk archives into a local cache.

Verify

Validate each archive’s GPG signature against the trusted-keys store before unpacking.

Install

Unpack files onto the filesystem, run pre/post scripts, update the local package database (/var/lib/dpkg, /var/lib/rpm, …) so future queries can answer “what’s installed” and “who owns this file.”

Five stages, five filesystem locations per manager. A quick map of where each stage’s state lives:

Stage

apt / dpkg

dnf / rpm

pacman

apk

zypper

Repos

/etc/apt/sources.list*

/etc/yum.repos.d/

/etc/pacman.conf

/etc/apk/repositories

/etc/zypp/repos.d/

Keys

/etc/apt/keyrings/

/etc/pki/rpm-gpg/

(in pacman.conf)

/etc/apk/keys/

(in zypp.conf)

Cache

/var/cache/apt/archives

/var/cache/dnf/

/var/cache/pacman/pkg/

/var/cache/apk/

/var/cache/zypp/

Database

/var/lib/dpkg/

/var/lib/rpm/

/var/lib/pacman/local/

/lib/apk/db/

/var/lib/zypp/

Format

.deb

.rpm

.pkg.tar.zst

.apk

.rpm

Logs

/var/log/{apt,dpkg}.log

/var/log/dnf.{log,rpm.log}

/var/log/pacman.log

/var/log/apk.log

/var/log/zypper.log

Beyond the native managers, three other distribution models coexist:

  • Universal / sandboxed, Flatpak, Snap, AppImage. Bundle their own runtime; bypass the distro’s libraries.

  • User-scoped, Homebrew, Nix, language managers (pip / npm / cargo / go). Install into the user’s home, no root.

  • From source, Autotools, CMake, Meson. Bypass packaging entirely, or build a package and feed it back to the native manager.

Repositories#

A repository is a signed catalog of packages the manager can install from. Three things define one. A URL or directory the manager can read. A signed index listing what is available, who built each package, and how to verify it. A pool (or archive, or cache) of the package files themselves at well-known paths under that URL.

The signed index is the trust anchor. The manager fetches it first, verifies the signature against the keys in the local keyring, and only then trusts the package names, versions, and checksums inside. A package archive copied off a mirror is useless to the manager without the matching index entry, and an index with a key the manager does not trust is refused.

Repository Layout per Manager#

Each ecosystem lays out the metadata differently. The substance is the same.

Manager

Index file(s)

Package pool

apt

dists/<release>/InRelease (signed) plus per-component Packages.gz / Packages.xz

pool/<component>/<initial>/<source>/...

dnf / yum

repodata/repomd.xml (signed) plus primary, filelists, other

flat directory per arch (Packages/)

pacman

<repo>.db.tar.zst (signed)

flat directory per repo, .pkg.tar.zst archives

apk

APKINDEX.tar.gz (signed)

flat directory, .apk archives

zypper

repodata/repomd.xml (signed; same as dnf)

per-arch Packages/ directories

Official Repository Tiers#

Each distro slices its catalog into tiers by license, support level, and freshness. The operator picks which tiers to enable.

Distro

Tiers

Notes

Debian

main, contrib, non-free, non-free-firmware

main is fully DFSG-compliant; contrib depends on non-free; non-free-firmware was split out in Debian 12.

Ubuntu

main, restricted, universe, multiverse

main + restricted are Canonical-supported; the rest are community-maintained.

RHEL / Rocky / Alma

BaseOS, AppStream, CRB

BaseOS is the host runtime; AppStream is app and runtime modules; CRB (CodeReady Builder) carries dev libraries.

Fedora

fedora, updates, updates-testing

Often paired with rpmfusion-free / rpmfusion-nonfree for codecs and proprietary drivers.

Arch

core, extra, multilib

core is the minimum bootable system; multilib adds 32-bit libraries; community merged into extra in 2023.

Alpine

main, community, testing

main is project-supported; community is contributor-maintained; testing is the staging ground.

Third-Party Channels#

Every ecosystem has an extension channel for software the distro itself does not ship. These bypass the distro’s review process and trust whoever signs them. Treat each one as a separate supply chain.

Channel

Ecosystem

What it is

PPA

Ubuntu

Personal Package Archive on Launchpad. Per-maintainer repository the operator adds with add-apt-repository.

EPEL

RHEL family

Extra Packages for Enterprise Linux. Fedora-maintained overflow for software RHEL does not include.

COPR

Fedora / RHEL

Cool Other Package Repo. Per-maintainer build service hosted by Fedora, similar to PPA.

AUR

Arch

Arch User Repository. PKGBUILD recipes the operator builds locally (yay, paru, makepkg). Source-side, not binary.

OBS

openSUSE / cross-distro

Open Build Service. Repositories built from source for any supported distro.

RPM Fusion

Fedora / RHEL

Non-free codecs, drivers, and content Fedora does not ship.

Package Formats#

A package is an archive with metadata. The metadata tells the manager what the package needs, what it provides, what scripts to run on install and removal, and where each file goes. The archive holds the files themselves.

Format

Archive structure

Metadata layer

.deb

ar archive containing debian-binary, control.tar.*, data.tar.*

control file plus preinst / postinst / prerm / postrm scripts; md5sums for installed files

.rpm

signed header plus a cpio archive (typically xz or zstd compressed)

the RPM header carries dependencies, scriptlets, the file list, and per-file digests

.pkg.tar.zst

zstandard-compressed tarball

.PKGINFO (metadata), .MTREE (file checksums), .INSTALL (scriptlets)

.apk

gzipped tar with three concatenated sections (signature, metadata, files)

.PKGINFO, .SIGN.RSA.*, .scripts.tar

The operator inspects any of these without installing them.

$ dpkg-deb -c package.deb                # list files in a .deb
$ dpkg-deb -e package.deb /tmp/control   # extract metadata
$ rpm2cpio package.rpm | cpio -idv       # unpack an .rpm
$ rpm -qip package.rpm                   # show .rpm metadata
$ bsdtar -tf package.pkg.tar.zst         # list files in an Arch package
$ tar -tzf package.apk                   # list files in an Alpine package

The same archive format repeats on the installed side. The package database (/var/lib/dpkg, /var/lib/rpm, /var/lib/pacman, /lib/apk/db) is the canonical record of which files came from which package, with the same digests the archive carried. Tamper detection (debsums, rpm -V, pacman -Qkk, apk audit) compares the on-disk files against that record.

apt (Debian / Ubuntu)#

The default package manager on Debian, Ubuntu, Kali, Mint, and any distribution downstream of Debian. apt is the user-facing front end; dpkg is the lower-level tool that operates on .deb files.

Repositories and keys#

The modern pattern: download the signing key into /etc/apt/keyrings/ and reference it from a sources file with Signed-By:. Never apt-key add; that command is deprecated and trusts the key for every repository on the system.

$ sudo install -m 0755 -d /etc/apt/keyrings
$ curl -fsSL https://download.docker.com/linux/debian/gpg | \
    sudo gpg --dearmor -o /etc/apt/keyrings/docker.gpg
$ sudo chmod a+r /etc/apt/keyrings/docker.gpg

$ sudo tee /etc/apt/sources.list.d/docker.sources >/dev/null <<EOF
$ Types: deb
$ URIs: https://download.docker.com/linux/debian
$ Suites: $(lsb_release -cs)
$ Components: stable
$ Architectures: amd64
$ Signed-By: /etc/apt/keyrings/docker.gpg
$ EOF

$ echo "deb [arch=amd64 signed-by=/etc/apt/keyrings/docker.gpg] \
     https://download.docker.com/linux/debian $(lsb_release -cs) stable" | \
     sudo tee /etc/apt/sources.list.d/docker.list

$ sudo apt update
$ sudo apt install docker-ce

How apt fetches#

apt does not speak HTTP itself. Each URI scheme in sources.list dispatches to a method handler under /usr/lib/apt/methods/ (http, https, ftp, file, copy, mirror, cdrom, store). The parent process pipes URLs to the handler over stdin and reads bytes back from stdout. apt update fetches index files; apt install fetches the actual .deb archives the resolver picked.

The pieces involved in a fetch:

        flowchart LR
  subgraph Client [client host]
    direction TB
    APT["apt / apt-get"]
    SRC["/etc/apt/sources.list*<br/>(repo URIs)"]
    CFG["/etc/apt/apt.conf.d/<br/>(proxy, retries, ...)"]
    KEYS["/etc/apt/keyrings/<br/>(GPG signing keys)"]
    METHODS["/usr/lib/apt/methods/<br/>http · https · ftp · file · ..."]
    LISTS["/var/lib/apt/lists/<br/>(index cache)"]
    CACHE["/var/cache/apt/archives/<br/>(.deb cache)"]
    DPKG["/var/lib/dpkg/<br/>(install db)"]
    APT --> SRC
    APT --> CFG
    APT --> METHODS
    APT --> KEYS
    METHODS --> LISTS
    METHODS --> CACHE
    CACHE --> DPKG
  end
  PROXY["HTTP/HTTPS proxy<br/>(squid, apt-cacher-ng)"]
  MIRROR["mirror<br/>archive.ubuntu.com,<br/>deb.debian.org, ..."]
  METHODS -->|via $https_proxy<br/>or Acquire::*::Proxy| PROXY
  METHODS -->|DIRECT| MIRROR
  PROXY --> MIRROR
    

The dynamic flow for a single fetch:

        sequenceDiagram
  participant A as apt
  participant H as /usr/lib/apt/methods/https
  participant P as proxy (optional)
  participant R as mirror (e.g. archive.ubuntu.com)
  A->>H: GET InRelease, Packages.{gz,xz}
  H->>P: TCP / TLS via $https_proxy
  P->>R: forward request
  R-->>P: signed index + package list
  P-->>H: response bytes
  H-->>A: cache to /var/lib/apt/lists/
  Note over A: verify InRelease signature against /etc/apt/keyrings/
  A->>A: resolve dep graph from local indexes
  A->>H: GET pool/main/n/nginx/nginx_*.deb
  H->>P: TCP / TLS
  P->>R: forward
  R-->>P: .deb bytes
  P-->>H: response
  H-->>A: stored in /var/cache/apt/archives/
  Note over A: SHA256 + GPG verified before unpack
  A->>A: dpkg unpack + maintainer scripts
    

Each fetch is a separate request; apt pipelines several in parallel per method handler (Acquire::Queue-Mode "host" + a worker per host).

The on-disk layout the sequence touches:

Path

Holds

/etc/apt/sources.list, /etc/apt/sources.list.d/

Repository URIs and signing-key references

/etc/apt/keyrings/

Per-repo GPG keys (modern Signed-By: form)

/etc/apt/apt.conf.d/

Drop-in config (proxy, retries, timeouts, pinning)

/var/lib/apt/lists/

Cached InRelease / Packages index files

/var/cache/apt/archives/

Downloaded .deb files (kept until apt clean)

/var/lib/dpkg/

Installed-package database (status, info/, etc.)

Proxies#

apt honors environment variables (http_proxy, https_proxy, ftp_proxy, no_proxy) but the durable place to set them is a drop-in under /etc/apt/apt.conf.d/. That way sudo apt update and unattended-upgrades see the same configuration.

$ sudo tee /etc/apt/apt.conf.d/95proxy >/dev/null <<'EOF'
Acquire::http::Proxy  "http://proxy.lan:3128";
Acquire::https::Proxy "http://proxy.lan:3128";
Acquire::ftp::Proxy   "http://proxy.lan:3128";

// Bypass the proxy for an internal mirror
Acquire::http::Proxy::mirror.lan "DIRECT";
EOF

For an organization-wide cache, run apt-cacher-ng (or squid-deb-proxy) on a host inside the network and point every client at it. The cache de-duplicates downloads of the same .deb across the fleet:

        sequenceDiagram
  participant C as client apt
  participant AC as apt-cacher-ng
  participant U as upstream mirror
  C->>AC: GET nginx_*.deb
  alt cached
    AC-->>C: serve from local store
  else miss
    AC->>U: GET nginx_*.deb
    U-->>AC: .deb bytes
    AC-->>C: stream to client
    Note over AC: kept in cache for the next client
  end
    

Other fetch knobs in apt.conf.d/:

Directive

Effect

Acquire::Retries "3";

Retry failed downloads

Acquire::http::Timeout "30";

Per-connection timeout (seconds)

Acquire::http::Pipeline-Depth "0";

Disable HTTP pipelining (some proxies misbehave)

Acquire::ForceIPv4 "true";

Skip IPv6 mirror records

Acquire::AllowInsecureRepositories "false";

Refuse unsigned Release files

APT::Sandbox::User "_apt";

Drop privileges in the method handler

Diagnose what apt is actually doing on the wire:

$ sudo apt -o Debug::Acquire::http=true update
$ sudo apt -o Debug::pkgAcquire::Worker=true update
$ /usr/lib/apt/methods/https </dev/null
$ sudo apt-get install --print-uris nginx

dnf (Fedora / RHEL)#

The default package manager on Fedora, RHEL 8+, AlmaLinux, Rocky Linux, and CentOS Stream. dnf is a rewrite of the older yum and accepts the same arguments, so transcripts and runbooks written for either tool generally work on the other.

Install, remove, search#

$ sudo dnf install nginx
$ sudo dnf install ./local.rpm
$ sudo dnf remove nginx
$ sudo dnf upgrade
$ sudo dnf upgrade nginx
$ sudo dnf autoremove
$ dnf search redis
$ dnf info nginx
$ rpm -qa | grep nginx
$ rpm -ql nginx
$ rpm -qf /usr/sbin/nginx

Repositories and keys#

Repos live in /etc/yum.repos.d/*.repo. Keys can be inlined as URLs in the .repo file (gpgkey=); dnf imports on first use after asking for confirmation. Or import a key explicitly with rpm --import.

$ sudo dnf install -y dnf-plugins-core
$ sudo dnf config-manager --add-repo \
    https://download.docker.com/linux/fedora/docker-ce.repo
$ sudo dnf install docker-ce

$ sudo tee /etc/yum.repos.d/example.repo >/dev/null <<EOF
$ [example]
$ name=Example Repository
$ baseurl=https://repo.example.com/rhel/9/x86_64
$ enabled=1
$ gpgcheck=1
$ gpgkey=https://repo.example.com/keys/RPM-GPG-KEY-example
$ EOF

$ sudo rpm --import https://repo.example.com/keys/RPM-GPG-KEY-example

$ sudo dnf repolist
$ sudo dnf config-manager --set-enabled example
$ sudo dnf config-manager --set-disabled example

pacman (Arch)#

The Arch package manager. A single config file (/etc/pacman.conf), a single command for install / remove / upgrade, and a rolling-release model where pacman -Syu always pulls the newest packages from the configured mirrors. AUR helpers like yay add user-contributed packages on top.

Install, remove, search#

$ sudo pacman -Syu
$ sudo pacman -S nginx
$ sudo pacman -U ./local.pkg.tar.zst
$ sudo pacman -R nginx
$ sudo pacman -Rs nginx
$ sudo pacman -Rns nginx
$ pacman -Ss redis
$ pacman -Qs redis
$ pacman -Qi nginx
$ pacman -Ql nginx
$ pacman -Qo /usr/bin/nginx

The Arch User Repository (AUR) is accessed via yay, paru, or makepkg.

Repositories and keys#

Repos are added as named [section] blocks in /etc/pacman.conf. Keys go through pacman-key so they end up signed by the local keyring, which pacman trusts.

$ sudo tee -a /etc/pacman.conf >/dev/null <<'EOF'

$ [example]
$ SigLevel = Required DatabaseOptional
$ Server = https://repo.example.com/arch/$arch
$ EOF

$ sudo pacman-key --recv-keys ABCD1234EF567890
$ sudo pacman-key --lsign-key  ABCD1234EF567890

$ sudo pacman-key --add example.pub
$ sudo pacman-key --lsign-key 'maintainer@example.com'

$ sudo pacman -Sy

apk (Alpine)#

Alpine’s package manager: tiny, fast, and container-friendly. apk ships in around a megabyte, which is a major reason Alpine is the default base image for so many minimal containers. Repositories live in /etc/apk/repositories; the main, community, and testing tiers parallel Debian’s archive areas.

Install, remove, search#

$ sudo apk update
$ sudo apk upgrade
$ sudo apk add nginx
$ sudo apk add --no-cache nginx
$ sudo apk del nginx
$ apk search redis
$ apk info nginx
$ apk info -L nginx
$ apk info --who-owns /usr/sbin/nginx

Repositories and keys#

Each line in /etc/apk/repositories is one repo URL. Public keys go in /etc/apk/keys/ as .rsa.pub files; apk trusts everything in that directory.

$ echo 'https://repo.example.com/alpine/v3.20/main' | \
    sudo tee -a /etc/apk/repositories

$ sudo wget -P /etc/apk/keys/ \
    https://repo.example.com/alpine/example.rsa.pub

$ sudo apk update
$ sudo apk add example-pkg

$ sudo sed -i '/community$/s/^#//' /etc/apk/repositories
$ echo 'https://dl-cdn.alpinelinux.org/alpine/edge/testing' | \
    sudo tee -a /etc/apk/repositories

zypper (openSUSE)#

Default on openSUSE Leap, Tumbleweed, and SUSE Linux Enterprise. zypper operates on the same RPM packages as dnf but with its own repo format (.repo files in /etc/zypp/repos.d/) and a transactional snapper integration for rollback on Btrfs roots.

Install, remove, search#

$ sudo zypper refresh
$ sudo zypper update
$ sudo zypper dist-upgrade
$ sudo zypper install nginx
$ sudo zypper remove nginx
$ zypper search redis
$ zypper info nginx
$ zypper search --installed-only redis

Repositories and keys#

zypper addrepo writes a .repo file under /etc/zypp/repos.d/. Keys are imported on first zypper refresh; zypper prompts before trusting a new key.

$ sudo zypper addrepo -f \
    https://download.opensuse.org/repositories/Example/openSUSE_Tumbleweed/Example.repo \
    example
$ sudo zypper refresh
$ sudo zypper install example-pkg

$ sudo zypper repos
$ sudo zypper modifyrepo --disable example
$ sudo zypper removerepo example

$ sudo rpm --import https://example.com/repo-key.asc

Universal Formats#

Cross-distribution package formats and language-agnostic managers. Each one bundles its dependencies so the same artifact runs across distros without depending on the host’s libraries, useful for desktop apps with niche requirements, and for any tool an operator wants to carry from one engagement to the next.

Flatpak#

Sandboxed desktop apps; runtime + app split. Best for GUI tools.

$ sudo flatpak remote-add --if-not-exists flathub \
    https://flathub.org/repo/flathub.flatpakrepo
$ flatpak install flathub org.mozilla.firefox
$ flatpak update
$ flatpak list
$ flatpak run org.mozilla.firefox

Snap#

A universal package format from Canonical. Auto-updates by default.

$ snap find code
$ sudo snap install code --classic
$ sudo snap refresh
$ snap list

AppImage#

Single-file portable executables. No install, just chmod +x.

$ chmod +x ./MyApp.AppImage
$ ./MyApp.AppImage

Homebrew#

Originally macOS, now first-class on Linux too.

$ /bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh)"
$ brew install ripgrep
$ brew upgrade
$ brew list

Nix#

Declarative, reproducible packages. The package store (/nix/store/) is content-addressed; multiple versions coexist.

$ nix-env -iA nixpkgs.ripgrep
$ nix profile install nixpkgs#ripgrep
$ nix-channel --update
$ nix-collect-garbage -d

Building from Source#

When no package exists, or the packaged version is too old, build from source. Each project picks one of a few standard build systems (autotools, cmake, meson, language-native ones like cargo or go build), so the operator’s job is to recognize the system in use and run the right invocation.

Autotools#

The traditional ./configure && make && make install dance. --prefix controls where files land; /usr/local is the unwritten standard for source-built software.

$ ./configure --prefix=/usr/local
$ make -j"$(nproc)"
$ sudo make install

CMake#

Modern cross-platform build generator. -S is the source directory, -B the build directory.

$ cmake -S . -B build -DCMAKE_BUILD_TYPE=Release
$ cmake --build build -j"$(nproc)"
$ sudo cmake --install build

Meson#

Faster than autotools, simpler than CMake. Uses ninja as the build backend.

$ meson setup build --buildtype=release
$ meson compile -C build
$ sudo meson install -C build

Packaging the result#

For anything beyond a one-off, build a real package instead of make install:

  • checkinstall, wrap make install and produce a .deb / .rpm.

  • dpkg-buildpackage (Debian), rpmbuild (RHEL), makepkg (Arch), native packaging from a spec file.

  • fpm, “effing package management”; build .deb / .rpm / .apk from a directory tree.

Common Tasks#

Identify the distribution and family. Pick the right tool.

$ cat /etc/os-release
$ command -v apt dnf yum pacman apk zypper
$ lsb_release -a 2>/dev/null

List installed packages. The software inventory.

$ dpkg -l 2>/dev/null | awk 'NR>5{print $2,$3}'
$ rpm -qa --queryformat '%{NAME} %{VERSION}\n' 2>/dev/null
$ pacman -Q 2>/dev/null
$ apk info -v 2>/dev/null

Audit package install history. When was what added.

$ grep -h 'install ' /var/log/dpkg.log* 2>/dev/null | tail -30
$ sudo dnf history list --reverse 2>/dev/null | head
$ grep -i installed /var/log/pacman.log 2>/dev/null | tail

Verify integrity. Find tampered packages.

$ sudo dpkg -V 2>/dev/null
$ sudo rpm -Va 2>/dev/null | head
$ sudo pacman -Qkk 2>/dev/null | grep -v '0 altered'

Identify out-of-repo binaries. Manual installs and side-loads.

$ apt list --installed 2>/dev/null | grep -i local
$ find /usr/local /opt -maxdepth 3 -type f -executable 2>/dev/null
$ ls -la /etc/apt/sources.list.d/ /etc/yum.repos.d/

Update, install, remove, hold. The four daily verbs.

$ sudo apt update && sudo apt -s upgrade
$ sudo apt install --no-install-recommends <pkg>
$ sudo apt remove --purge <pkg>
$ sudo apt-mark hold <pkg>

Search for a package. By name or by description.

$ apt search <term>; apt-cache search <term>
$ dnf search <term> 2>/dev/null
$ pacman -Ss <term> 2>/dev/null
$ apk search <term> 2>/dev/null

Show package details. Version, deps, maintainer, files.

$ apt show <pkg>; dpkg -s <pkg>; dpkg -L <pkg>
$ rpm -qi <pkg>; rpm -ql <pkg>; rpm -qR <pkg>
$ pacman -Qi <pkg>; pacman -Ql <pkg>

Find which package owns a file. The reverse lookup.

$ dpkg -S /usr/bin/curl
$ rpm -qf /usr/bin/curl
$ pacman -Qo /usr/bin/curl
$ apk info --who-owns /usr/bin/curl

Manage repositories and keys. Add, remove, refresh.

$ ls /etc/apt/sources.list.d/ /etc/yum.repos.d/
$ sudo add-apt-repository ppa:<owner>/<ppa>
$ sudo apt-key list 2>/dev/null; ls /etc/apt/trusted.gpg.d/
$ sudo dnf config-manager --add-repo <url> 2>/dev/null

Patch security updates only. Minimum-impact upgrade path.

$ sudo unattended-upgrade --dry-run -d 2>/dev/null
$ sudo apt list --upgradable 2>/dev/null
$ sudo dnf updateinfo list security 2>/dev/null
$ sudo dnf upgrade --security 2>/dev/null

Roll back a bad upgrade. Pin a known-good version.

$ apt list -a <pkg> 2>/dev/null
$ sudo apt install <pkg>=<version>
$ sudo dnf history undo <id> 2>/dev/null
$ sudo pacman -U /var/cache/pacman/pkg/<pkg>-<old>.pkg.tar.zst

Files & paths#

Configuration, repository, key, cache, database, and log locations per package manager. Knowing where each manager stores state is what lets you mirror a repo, swap a key, free disk space, or audit what is configured before installing anything new.

apt / dpkg (Debian / Ubuntu)#

  • /etc/apt/sources.list, main repository list.

  • /etc/apt/sources.list.d/*.list, per-repo extra files.

  • /etc/apt/sources.list.d/*.sources, DEB822 format (newer).

  • /etc/apt/preferences / preferences.d/, pinning and priorities.

  • /etc/apt/apt.conf / apt.conf.d/*, apt behavior tuning.

  • /etc/apt/keyrings/, repository signing keys (modern path).

  • /etc/apt/trusted.gpg.d/, legacy keyring location.

  • /var/lib/apt/lists/, downloaded package indexes.

  • /var/cache/apt/archives/, downloaded .deb files.

  • /var/lib/dpkg/status, the installed-package database.

  • /var/lib/dpkg/info/<pkg>.{conffiles,md5sums,list,...}, per-package metadata.

  • /var/log/dpkg.log, install / remove history.

  • /var/log/apt/history.log, apt operations.

  • /etc/dpkg/dpkg.cfg, dpkg defaults.

dnf / rpm (Fedora / RHEL)#

  • /etc/yum.repos.d/*.repo, repository definitions.

  • /etc/dnf/dnf.conf, dnf configuration.

  • /etc/yum.conf, yum configuration (legacy).

  • /etc/pki/rpm-gpg/, repository signing keys.

  • /var/cache/dnf/, metadata and downloaded RPMs.

  • /var/lib/rpm/, the RPM database.

  • /var/log/dnf.log / dnf.rpm.log / dnf.librepo.log, operation logs.

  • /var/log/yum.log, yum history (legacy).

pacman (Arch)#

  • /etc/pacman.conf, pacman configuration.

  • /etc/pacman.d/mirrorlist, mirror selection.

  • /etc/pacman.d/hooks/, post-transaction hooks.

  • /var/cache/pacman/pkg/, downloaded packages.

  • /var/lib/pacman/local/, installed package metadata.

  • /var/lib/pacman/sync/, repository databases.

  • /var/log/pacman.log, transaction log.

apk (Alpine)#

  • /etc/apk/repositories, repository URLs.

  • /etc/apk/world, explicitly-installed packages (the user’s “wishlist”).

  • /etc/apk/keys/, signing keys.

  • /var/cache/apk/, package cache.

  • /lib/apk/db/, installed-package database.

zypper (openSUSE)#

  • /etc/zypp/zypp.conf, zypper configuration.

  • /etc/zypp/repos.d/*.repo, repositories.

  • /var/cache/zypp/, cache.

  • /var/log/zypper.log, operations.

Cross-distribution / language managers#

  • Flatpak, /var/lib/flatpak/ system, ~/.local/share/flatpak/ user.

  • Snap, /var/lib/snapd/, /var/snap/<pkg>/ data, /snap/ mounts.

  • Homebrew (Linux), /home/linuxbrew/.linuxbrew/.

  • Nix, /nix/store/, /etc/nixos/configuration.nix (NixOS).

  • pip: ~/.config/pip/pip.conf, ~/.cache/pip/.

  • npm: ~/.npmrc, ~/.npm/ (cache), node_modules/ per project.

  • cargo: ~/.cargo/config.toml, ~/.cargo/registry/.

  • go: $GOPATH (default ~/go), ~/go/pkg/mod/.

References#

  • man 8 apt, man 8 apt-get, man 1 dpkg, man 5 sources.list (Debian / Ubuntu).

  • man 8 dnf, man 8 yum, man 8 rpm, man 5 dnf.conf (Red Hat family).

  • man 8 pacman, man 5 pacman.conf, man 8 makepkg (Arch).

  • man 8 apk (Alpine).

  • man 8 zypper (openSUSE).

  • man 8 emerge, man 5 portage (Gentoo).

  • Distributions for which family ships each manager by default.

  • Services for systemd timers that drive unattended upgrades.

  • Hardening for signature verification, third-party-repo posture, and lockdown of unsigned modules.

  • Python for pip / uv / poetry ecosystem detail.

  • Debian Policy Manual

  • Fedora Packaging Guidelines

  • Arch packaging

  • Repology (cross-distro package versions)