This is Round 2 of Domain 5 in my Linux Mastery: Road to Cloud series. If Round 1 was about learning what package management tools exist and how to use them, Round 2 is about understanding what’s actually happening underneath — where files live, what states packages go through, what breaks and why, and how to recover when things go wrong.
By the end of this round, the goal isn’t to memorize every command and path cold. The goal is to know what layer to look at when something breaks, what vocabulary to use, and what questions to ask. The paths and exact syntax stick naturally through real use — not through memorization.
What Round 2 Actually Covers
Round 1 covered the basics: installing, removing, updating packages with APT, and understanding what dpkg is. Round 2 goes deeper into five areas:
APT internals — what actually happens when you run apt update, where the indexes live, how APT decides which version to install, and what the cache is doing.
dpkg internals — the package state machine (unpacked → configured → installed), the status database, what the info directory contains, and how to read status codes properly.
Failure states and recovery — lock files, partial installs, half-configured packages, broken dependencies, and what to do when apt refuses to run.
Repository and security management — GPG keys, sources.list structure, the modern way to add third-party repos, pinning, and priority logic.
Real operational awareness — unattended-upgrades, network failure behavior, stale metadata, and what changes after a libc upgrade on a running server.
The Filesystem Layer — Paths You Need to Know
Before touching commands, I walked these paths on my actual server. Theory becomes real the moment you see what’s actually inside these directories.
1. /var/lib/apt/lists/
ls /var/lib/apt/lists/
This is where APT stores the package indexes downloaded by apt update. The files are named after the repo URLs they came from. When you search for a package or check what version is available, APT reads from here — not from the internet. If these files are stale or a repo was unreachable during your last update, APT is working from old data without telling you.
2. /var/cache/apt/archives/
ls /var/cache/apt/archives/
du -sh /var/cache/apt/archives/
Every .deb file APT downloads before installing sits here first. On a server that has been running for a while, this can quietly consume significant disk space. This is what apt clean wipes. Run apt autoclean instead if you want to only remove packages that can no longer be downloaded (i.e., outdated versions).
3. /etc/apt/sources.list and /etc/apt/sources.list.d/
cat /etc/apt/sources.list
ls /etc/apt/sources.list.d/
Your repo configuration lives here. The sources.list.d/ directory is where every third-party tool you add drops its own file — Docker, Nginx official, GitHub CLI, all of them. This is where repo debt accumulates. If you’ve added repos and forgotten about them, this is where you find them. Always prefer adding repos via sources.list.d/ rather than editing sources.list directly — it keeps things isolated and easier to remove cleanly.
4. /etc/apt/trusted.gpg.d/
ls /etc/apt/trusted.gpg.d/
The signing keys for your repos live here, one .gpg or .asc file per trusted repository. APT refuses to use a repo if the key isn’t here. The old way was apt-key add, which dumped everything into a single shared keyring — a security problem because any trusted key could sign packages from any repo. The modern approach stores keys separately, scoped to the repo they’re for.
5. /var/lib/dpkg/status — the most important file in this domain
grep -A 10 "^Package: nginx" /var/lib/dpkg/status
This file is the single source of truth for what dpkg believes is installed on your system. Every package, its version, its dependencies, and its current state is recorded here. APT reads this file too. If this gets corrupted, your entire package management system breaks. It’s worth knowing it exists and what it looks like — not to edit it manually, but to understand why certain dpkg commands behave the way they do.
6. /var/lib/dpkg/info/
ls /var/lib/dpkg/info/ | grep nginx
cat /var/lib/dpkg/info/nginx.list | head -20
For every installed package there’s a set of files in here: a .list file containing every file the package owns, and scripts like .postinst, .prerm, .postrm that run at install/remove time. When you run dpkg -L nginx, it reads from here. When you run dpkg -S /usr/sbin/nginx to find which package owns a file, it searches these lists.
7. /var/lib/dpkg/lock and /var/lib/apt/lists/lock
ls -la /var/lib/dpkg/lock
lsof /var/lib/dpkg/lock
These lock files prevent two apt/dpkg processes from running simultaneously and corrupting the package database. The most common junior mistake is to kill the process holding the lock to “free it up.” If that process was in the middle of unpacking or configuring a package, you’ve now left your system in a broken half-installed state. Always use lsof to identify what’s holding the lock, then wait for it to finish — or verify it’s genuinely dead before doing anything else.
8. /var/log/apt/history.log
tail -50 /var/log/apt/history.log
Every install, remove, and upgrade is logged here with a timestamp and the exact package versions. When something breaks after an upgrade and you need to know what changed, this is the first place to look. On a production server this log is your audit trail.
9. /var/log/dpkg.log
tail -50 /var/log/dpkg.log
This is the lower-level record of every dpkg operation, including the phase transitions — unpacked, half-configured, configured, installed. If a package got stuck in a partial state, the exact phase where it failed is recorded here. This is where you look when apt install exits mid-way and leaves something broken.
10. /etc/apt/preferences.d/
ls /etc/apt/preferences.d/
cat /etc/apt/preferences 2>/dev/null || echo "no preferences file"
APT pinning configuration lives here. On most servers this directory is empty, which means APT uses its default priority system (500 for standard repos). The moment you need to freeze a package at a specific version on a production server — or force APT to prefer one repo over another — this is where you configure it.
The Commands Layer — 32 Commands Organized by Purpose
These aren’t commands to memorize. They’re commands to run at least once, read the output of, and understand what question each one answers. That’s enough.
Inspection — Reading System State
apt-cache policy <package> # installed version, candidate version, repo priorities
apt-cache show <package> # full package metadata
apt-cache madison <package> # all available versions from all repos
apt-cache rdepends <package> # what other packages depend on this one
dpkg -l # list all packages with status codes
dpkg -l | grep "^rc" # find removed-but-not-purged packages
dpkg -L <package> # list all files owned by a package
dpkg -S <file> # which package owns this file
dpkg --get-selections # export current package selections
apt-mark showhold # list packages currently on hold
apt list --upgradable # show what has pending updates
State Management — Changing Package State
apt-mark hold <package> # freeze a package at its current version
apt-mark unhold <package> # release the freeze
apt install -f # fix broken dependency state
apt --fix-broken install # same thing, APT layer version
dpkg --configure -a # finish configuring any unpacked packages
apt install --reinstall <package> # reinstall without removing first
apt purge <package> # remove package AND its config files
apt autoremove # remove packages no longer needed by anything
Troubleshooting — Diagnosing Broken States
lsof /var/lib/dpkg/lock # who is holding the dpkg lock
lsof /var/lib/apt/lists/lock # who is holding the apt lists lock
fuser /var/lib/dpkg/lock # alternative to lsof for finding lock holder
apt-get --simulate upgrade # dry run — shows what would change without doing it
dpkg --audit # find partially installed or broken packages
Repository and Version Management
apt install <package>=<version> # install a specific version
dpkg -i <file>.deb # install a manually downloaded .deb file
dpkg -c <file>.deb # inspect contents of a .deb without installing
dpkg-reconfigure <package> # re-run a package's configuration wizard
apt full-upgrade # upgrade including handling dependency changes
ls /etc/apt/trusted.gpg.d/ # check which repo signing keys are trusted
Understanding Package States
This is one of the most important concepts in Round 2. dpkg doesn’t install a package in one step — it goes through phases, and failures can happen between them.
The normal flow looks like this:
config-files → package was removed but config files kept
unpacked → files extracted, post-install script not yet run
half-configured → post-install script started but didn't complete
installed → fully done
When you see half-configured in a log, it doesn’t automatically mean something is broken. During a healthy install, dpkg logs half-configured as a checkpoint while the configuration script is running — you’ll see it followed immediately by installed. That’s normal.
It only means something is broken if the log ends on half-configured or unpacked without ever reaching installed. In that case, run:
sudo dpkg --configure -a
That command attempts to finish configuring everything that’s stuck in an incomplete state.
APT Priority System
When the same package exists in multiple repos at different versions, APT doesn’t pick randomly. It uses a priority system:
- 100 — an already-installed package version
- 500 — packages from a standard configured repo (default)
- 990 — packages from a repo marked as the target release
- 1000+ — pinned packages that APT will install even if it means a downgrade
- Below 0 — APT will never automatically select this version
The candidate version is the version APT has selected to install based on these priorities. You can inspect it with:
apt-cache policy <package>
Look for the line marked Candidate:. If you want to override APT’s choice — for example, to keep a specific version on a production server — you configure that in /etc/apt/preferences.d/.
Lock Files — The Most Common Operational Failure
The single most frequent package management failure on real servers is this error:
E: Could not get lock /var/lib/dpkg/lock-frontend
This happens when another process is already using APT or dpkg — most commonly unattended-upgrades running in the background. The correct response is:
# Step 1 — find what's holding the lock
sudo lsof /var/lib/dpkg/lock
sudo lsof /var/lib/dpkg/lock-frontend
# Step 2 — if it's a legitimate process, wait for it to finish
# Step 3 — if the process is genuinely dead (e.g. after a crash), THEN you can remove the lock
sudo rm /var/lib/dpkg/lock
sudo rm /var/lib/dpkg/lock-frontend
sudo dpkg --configure -a
The dangerous path is killing the process holding the lock without checking what it was doing. If it was mid-install, you’re now left with a half-unpacked package and a broken dpkg state.
unattended-upgrades — What’s Running in the Background
Ubuntu enables unattended-upgrades by default. It runs automatically and applies security updates without you doing anything. This is the correct behavior for a server — security patches shouldn’t wait for a human to remember to run apt upgrade.
Check if it’s active:
systemctl status unattended-upgrades
cat /var/log/unattended-upgrades/unattended-upgrades.log | tail -50
One thing that catches people off guard: after unattended-upgrades updates a core library like libc, running services are still using the old version in memory until they restart. On a production server you’d run:
sudo needrestart
This tells you which services need restarting to pick up the newly installed library versions. Skipping this step means your services are still running against the old, potentially vulnerable code even though the package is updated on disk.
A Real Incident From the Lab
While exploring the dpkg log during this round, I found entries from an hour earlier that I hadn’t triggered manually:
2026-03-16 17:09:16 status unpacked sudo:amd64 1.9.15p5-3ubuntu5.24.04.2
2026-03-16 17:09:16 status half-configured sudo:amd64 1.9.15p5-3ubuntu5.24.04.2
2026-03-16 17:09:16 status installed sudo:amd64 1.9.15p5-3ubuntu5.24.04.2
2026-03-16 17:09:19 status half-configured libc-bin:amd64 2.39-0ubuntu8.7
2026-03-16 17:09:19 status installed libc-bin:amd64 2.39-0ubuntu8.7
First instinct was that something was wrong. But reading the log properly: every package that went through half-configured also reached installed immediately after. All three packages — sudo, man-db, and libc-bin — completed successfully. The half-configured entries are normal phase transition checkpoints, not failures.
What actually happened: unattended-upgrades ran at 17:09 and applied security patches to sudo and glibc. The log in /var/log/apt/history.log confirmed this. The correct follow-up was to run needrestart to check if any services needed restarting after the libc update.
The lesson: knowing how to read dpkg.log turned a potentially alarming discovery into a five-minute investigation with a clear answer.
Round 2 Self-Test Questions
These are the questions I used to verify my own understanding before moving on. If you can answer these without looking things up, you have a solid Round 2 foundation. You don’t need to recite exact paths from memory — you need to know what layer to look at and what the answer means.
APT Internals & Cache
- What is the APT cache and where does it live on disk? What command cleans it, and why would you care about disk space there on a server?
- What is the difference between
apt updateandapt upgrade? What doesapt updateactually do — what file does it update and where? - What is
apt full-upgradeand how does it differ fromapt upgrade? When would you use one over the other? - After running
apt update, where does APT store the downloaded package index files? - What does
apt-cache policy <package>tell you? - What is the difference between
apt installandapt-get install? Is one preferred over the other in scripts?
dpkg Internals
- What is dpkg, and what is its relationship to APT? Which layer sits on top of which?
- What do the status codes in
dpkg -lmean — for exampleii,rc,iU? - What does
dpkg -L <package>do? How is it different fromdpkg -S <file>? - You have a
.debfile downloaded manually. What command installs it? What command inspects its contents before installing? - What is the dpkg status database and where is it located?
- A package shows status
rcindpkg -l. What does that mean and how do you fully purge it? - What is the difference between
apt removeandapt purge?
Package States and Recovery
- What are the two main phases dpkg goes through when installing a package? What is the system state called when phase one completes but phase two has not?
- What is the difference between
unpackedandconfiguredin dpkg’s status model? - What does a
half-installedstate mean? How do you recover from it? - You run
apt upgradeand it exits mid-way. What is the first command you should run next? - You see
half-configuredin your dpkg log. How do you determine if this is a failed state or a normal transition checkpoint?
Lock Files
- What are
/var/lib/dpkg/lockand/var/lib/apt/lists/lock? What does each one guard against? - You get “could not get lock /var/lib/dpkg/lock.” What is the correct investigation sequence?
- A junior admin kills the process holding the dpkg lock. What is the risk versus waiting?
- When is it actually safe to manually delete a lock file?
Repository Management
- What is the syntax of a single entry in
/etc/apt/sources.list? Break down each field. - What is a GPG key in the context of APT repos? What happens if you add a repo without its key?
- What is the modern way to add a third-party repo’s signing key? What was the old way and why was it deprecated?
- What is a PPA and what are the security implications of adding one?
Dependency Resolution
- What does it mean for a package to be “held back”? How do you place a package on hold?
- What are orphaned packages? What command removes them and what risk does blindly running it carry?
- What is a virtual package in Debian/APT? Give a real example.
- What does
apt install -fdo and when do you need it?
APT Priority and Version Selection
- What are the default APT priority values for an installed package, a package from a standard repo, and a pinned package?
- What does a priority of 100 vs 500 vs 990 mean in APT’s selection logic?
- Without explicit pinning, how does APT decide which version to install when the same package exists in multiple repos?
- What is the “candidate version” and how do you inspect it?
- What is APT pinning and where is it configured?
- What does it mean when APT says a package is “kept back”?
Security and Updates
- What is
unattended-upgrades? What does it do by default and how do you check if it’s active? - After a libc upgrade runs automatically, what additional step should you take on a production server?
- What does
apt-get --simulate upgradedo and when is it useful? - What log file records all APT activity and where is it?
Network Failures
- You run
apt updateand one repository returns a connection error. Does APT abort entirely or continue? - What is “stale metadata” in APT? What are the symptoms of running
apt upgradeagainst an outdated index? - A third-party repo goes offline permanently. What problems does this cause and how do you remove it cleanly?
- APT reaches the repo server but the Release file signature fails. Why is this more serious than a connection timeout?
Troubleshooting Broken States
- You get “dpkg was interrupted, you must manually run dpkg –configure -a.” What caused this and what do you do?
- apt upgrade fails mid-way due to a disk full error. What is your recovery sequence?
- What does
apt install --reinstall <package>do and when would you use it? - A package’s post-installation script fails. How do you find what went wrong?
Snap and Flatpak (Awareness)
- What is Snap and how does it differ architecturally from APT packages?
- What is a snap “channel”? What is the difference between stable, candidate, beta, and edge?
- What is Flatpak and what is Flathub?
- What are the main criticisms of Snap packages in production environments?
Practical Scenarios
- You need to downgrade a package to a specific older version. Walk through how you’d do it.
- You need to find which package provides the command
netstat. What command do you use? - A colleague says “just run apt upgrade every week and you’re fine.” What’s wrong with that on a production server?
- You want to replicate the exact package set from one server onto a new server. How do you export and import the package list?
- What is
dpkg-reconfigureand when would you use it?
What Round 2 Competency Actually Means
After completing this round, the benchmark isn’t “can I recite every path and flag from memory.” The benchmark is: when something breaks, do I know what layer to look at, what questions to ask, and what vocabulary to use?
If unattended-upgrades runs in the background and you see unfamiliar entries in your dpkg log, you read them — you don’t panic. If apt refuses to run because of a lock error, you investigate before doing anything — you don’t kill processes blindly. If a package ends up in a half-configured state, you know what command finishes the job.
That’s what Round 2 is building. Round 3 will push into real incident simulation — broken package states thrown at you with no warning, and you diagnose them from scratch.
This post is part of the Linux Mastery: Road to Cloud series documenting my self-directed path from zero to Junior Cloud/DevOps Engineer. All labs run on a live Ubuntu server at limonlab.online.