Two Ubuntu servers that were built from the same image both run `apt install nginx` and end up with different versions. Using `apt-cache policy`, how do you determine which repository a package's candidate version comes from and why apt picked it?
answer
- installed, candidate, version table
- every version lists its origin
- 500 ordinary, 100 backports and installed
- non-default number means a preferences file
- bare policy lists all package files
basics
~20 sRun apt-cache policy with the package name on both hosts. It prints the installed version, the candidate apt would install, and a version table listing each available version with its priority and origin repository, so you can see which source won and which sources differ between the machines.
solid answer
~40 s`apt-cache policy nginx` answers it directly: the `Installed:` and `Candidate:` lines say what is there and what apt would choose, and the version table beneath lists every version apt knows of, each with a numeric priority and the archive it came from — origin URL, suite and component. Comparing that table across the two hosts almost always exposes the cause: one machine has an extra source under `/etc/apt/sources.list.d/`, or has `-backports` or a vendor repository enabled, or carries a preferences file that raises one origin's priority. `apt-cache policy` with no arguments shows the whole picture — every package file with its priority and origin — which is the quickest way to spot a source the other machine does not have. Once you know the origin, `apt-get install nginx=<version>` or `nginx/<suite>` pins the choice explicitly.
code
bash · 11 lines# Which version would apt install, and from where?
apt-cache policy nginx
# Every index apt knows, with priority and release fields
apt-cache policy
# Compact availability listing
apt-cache madison nginx
# Make the choice explicit
apt-get install -y nginx=1.24.0-2ubuntu7.1go deeper
Know that apt-cache policy with a package name shows what is installed, what apt would install next, and where that version comes from. Recognise that different machines can have different sources enabled.
Read the whole version table: priorities, the origin line under each version, and the dpkg status pseudo-source. Explain why 500 is ordinary and why a backports archive sits at 100.
Use the bare form to diff two hosts' package files during a drift investigation, distinguish an extra source from an enabled suite from a preferences file, and then make the choice explicit with the version or suite syntax rather than leaving it to defaults.
Own how versions are determined across the estate: which third-party sources are permitted, whether builds must be reproducible against a snapshot mirror, and how drift between supposedly identical hosts is detected before an incident surfaces it.
## Reading the output ``` $ apt-cache policy nginx nginx: Installed: 1.24.0-2ubuntu7.1 Candidate: 1.24.0-2ubuntu7.1 Version table: *** 1.24.0-2ubuntu7.1 500 500 http://archive.ubuntu.com/ubuntu noble-updates/main amd64 Packages 100 /var/lib/dpkg/status 1.24.0-2ubuntu7 500 500 http://archive.ubuntu.com/ubuntu noble/main amd64 Packages ``` Four things to take from it: * **Installed** is what dpkg has now; `(none)` if absent. * **Candidate** is what an `apt install` or `apt upgrade` would move to. If Candidate equals Installed, apt considers the package current — regardless of what exists elsewhere in the world. * `***` marks the installed version in the table. * Each version is followed by its effective priority, then indented lines naming every source that offers it. `100 /var/lib/dpkg/status` is not a repository — it is the pseudo-source representing the installed copy. ## Where the priorities come from Apt assigns default priorities and then picks the highest-priority version, using the newest as a tiebreak within the same priority: * **500** — an ordinary enabled repository. Almost everything you see is 500. * **100** — the currently installed version, and archives marked `NotAutomatic` together with `ButAutomaticUpgrades`; Debian's `-backports` is the canonical example, which is why a backport is available but never installs by itself. * **1** — archives marked `NotAutomatic` only, such as Debian `experimental`. Available on request, never chosen automatically. Anything else in the table means somebody wrote a preferences file. `/etc/apt/preferences` and `/etc/apt/preferences.d/*` can raise or lower a priority for a package, an origin or a release, and their effect shows up here as a number that is not one of the defaults. That is the single most useful property of this command: it shows the *effect* of the configuration, so you never have to reason about the pin rules from the files alone. ## Diagnosing the two-host divergence Run the bare form on both machines: ``` $ apt-cache policy Package files: 100 /var/lib/dpkg/status release a=now 500 https://nginx.org/packages/ubuntu noble/nginx amd64 Packages release o=nginx,a=noble,n=noble,l=nginx,c=nginx,b=amd64 origin nginx.org 500 http://archive.ubuntu.com/ubuntu noble-updates/main amd64 Packages release v=24.04,o=Ubuntu,a=noble-updates,n=noble,c=main,b=amd64 ``` This lists every index apt has, with its priority and its release fields. Diffing the two hosts' output usually ends the investigation in one step, because the causes are few: 1. **An extra source file.** `/etc/apt/sources.list.d/` holds either one-line `.list` entries or deb822 `.sources` files with `Types:`, `URIs:`, `Suites:`, `Components:` and `Signed-By:` fields — recent Ubuntu ships its own archive that way. One host has a vendor or PPA source the other lacks. 2. **A different suite enabled.** `-updates`, `-security` or `-backports` present on one machine only. 3. **A preferences file** raising a vendor repository above the distribution's, so a third-party build wins even when the distribution's is newer. 4. **A different index age.** If one host has not run `apt update` recently, its candidate is simply older; the version table will show fewer versions. `apt-cache madison nginx` gives a compact one-line-per-version listing of the same availability data, which is convenient when you only want the version-to-suite mapping. ## Making the choice explicit Once you know which origin you want, stop relying on the default: ```bash apt-get install nginx=1.24.0-2ubuntu7.1 apt-get install nginx/noble-backports ``` The `=version` form demands an exact version; the `/suite` form tells apt to take the candidate from that release, pulling dependencies from it as needed. Both fail loudly if what you asked for is unavailable, which is what you want in provisioning — far better than a silent divergence discovered later. ## Why this belongs in the incident toolkit "Same image, different version" is a configuration-drift symptom, and the instinct to compare installed versions across hosts is only half the job. The version table shows *why*, and it distinguishes the four causes above in seconds — which matters because the fixes are entirely different: remove a source, enable a suite, delete a pin, or run an update.
- `apt-cache policy` shows a newer version in the table, but Candidate stays on the older one. What does that tell you?That the newer version's source carries a lower priority than the one apt is choosing. Either it comes from an archive marked NotAutomatic — Debian backports sit at 100, so they are available but never selected on their own — or a preferences file has lowered that origin deliberately. Install from it explicitly with the `pkg/suite` form when you want it.
- Why does `100 /var/lib/dpkg/status` appear as a source in the version table?It is the pseudo-source that represents the currently installed copy, priority 100. Its presence is what keeps apt from downgrading you to a repository version merely because it is offered: a repository at the default 500 outranks it, but an archive at priority 1 or a lowered pin does not. It is a bookkeeping entry, not something you can configure away.
- How do you make a provisioning run install one exact nginx version regardless of what the sources offer?Use the explicit `apt-get install nginx=1.24.0-2ubuntu7.1` form. It fails loudly if that version is not in any enabled source, which is the behaviour you want — the alternative is a silent divergence between hosts. Bear in mind the exact version stays available only while it is current in the pool, so long-lived pinned builds need a snapshot mirror behind them.
saying these in an interview costs you the question
- Assumes the candidate is always the newest version available
- Reads the dpkg status pseudo-source as a repository
- Compares installed versions across hosts without comparing sources
- Thinks a backport installs automatically once enabled
- Ignores preferences.d when a priority looks unusual