Skip to content

dpkg and apt

dpkg installs and queries individual .deb packages; apt resolves dependencies from repositories on Debian and Ubuntu. The split mirrors rpm and dnf, with Debian-specific details such as configuration purging and package holds.

Track: Core · Interview weight: Med


Must-Know Facts

Fact Value Verify with
Installed packages dpkg -l (ii = installed) dpkg -l bash
Status and dependencies dpkg -s <pkg> dpkg -s openssh-server
Files of a package dpkg -L <pkg> dpkg -L openssh-server
Owner of a file dpkg -S <path> dpkg -S /usr/sbin/sshd
Package for a file not installed apt-file search (package apt-file) apt-file search -x '/usr/bin/dig$'
Refresh indexes apt update; install and upgrade never refresh by themselves apt update
Remove vs purge remove keeps configuration files (rc); purge deletes them dpkg -l <pkg>
Unused dependencies apt autoremove apt autoremove --dry-run
Candidate version and origin apt-cache policy <pkg> apt-cache policy nginx
Hold a version apt-mark hold <pkg> apt-mark showhold
Verify files dpkg --verify, debsums -c (-e for config files) sudo debsums -ce openssh-client
History /var/log/apt/history.log, /var/log/dpkg.log tail /var/log/apt/history.log
Scripts Use apt-get; apt warns that its CLI is not stable and waits on locks apt-get -y install

Querying the dpkg Database

dpkg -l bash nosuchpkg
dpkg -l | grep -c '^ii'
dpkg-query -W -f='${Package} ${Version}\n' 'openssh*'
dpkg -s openssh-server | grep -E '^(Package|Status|Version)'
dpkg -s openssh-server | grep -A3 '^Conffiles'
dpkg -S /usr/sbin/sshd /etc/ssh/ssh_config

Output:

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  bash           5.2.21-2ubuntu4 amd64        GNU Bourne Again SHell
dpkg-query: no packages found matching nosuchpkg
485
openssh-client 1:9.6p1-3ubuntu13.18
openssh-server 1:9.6p1-3ubuntu13.18
openssh-sftp-server 1:9.6p1-3ubuntu13.18
openssh-sk-helper 
Package: openssh-server
Status: install ok installed
Version: 1:9.6p1-3ubuntu13.18
Conffiles:
 /etc/default/ssh 500e3cf069fe9a7b9936108eb9d9c035
 /etc/init.d/ssh 3649a6fe8c18ad1d5245fd91737de507
 /etc/pam.d/sshd 8b4c7a12b031424b2a9946881da59812
openssh-server: /usr/sbin/sshd
openssh-client: /etc/ssh/ssh_config

openssh-sk-helper has no version: dpkg-query -W lists packages the database knows about, including ones that are not installed.

dpkg -l code Meaning
ii Installed
rc Removed, configuration files remain
un Not installed
hi Installed and held
iU, iF Unpacked or half-configured: an interrupted install

The version 1:9.6p1-3ubuntu13.18 reads as epoch 1, upstream version 9.6p1, Debian revision 3ubuntu13.18.


Verifying Installed Files

echo "# local change" | sudo tee -a /etc/ssh/ssh_config >/dev/null
sudo chmod 700 /usr/bin/scp
dpkg --verify openssh-client
sudo debsums -c openssh-client; echo "rc=$?"
sudo debsums -ce openssh-client

Output:

??5?????? c /etc/ssh/ssh_config
?????????   /usr/bin/scp
rc=0
/etc/ssh/ssh_config

dpkg --verify checks only the MD5 digest (5); the ? marks for scp mean the unprivileged caller could not read the file, not that it changed. debsums -c skips configuration files unless -e is given.


Installing, Removing and Purging

apt-cache policy nginx | head -4
apt show nginx 2>/dev/null | grep -E '^(Package|Version|Section|Origin|Depends)'
sudo DEBIAN_FRONTEND=noninteractive apt-get install -y nginx
dpkg -l nginx | tail -1
sudo apt-get remove -y nginx
dpkg -l nginx nginx-common | tail -2
sudo apt-get purge -y nginx-common
sudo apt-get autoremove -y

Output:

nginx:
  Installed: (none)
  Candidate: 1.24.0-2ubuntu7.18
  Version table:
Package: nginx
Version: 1.24.0-2ubuntu7.18
Section: web
Origin: Ubuntu
Original-Maintainer: Debian Nginx Maintainers <pkg-nginx-maintainers@alioth-lists.debian.net>
Depends: libc6 (>= 2.34), libcrypt1 (>= 1:4.1.0), libpcre2-8-0 (>= 10.22), libssl3t64 (>= 3.0.0), zlib1g (>= 1:1.1.4), iproute2, nginx-common (= 1.24.0-2ubuntu7.18)
# ... (trimmed)
invoke-rc.d: policy-rc.d denied execution of start.
# ... (trimmed)
ii  nginx          1.24.0-2ubuntu7.18 amd64        small, powerful, scalable web/proxy server
# ... (trimmed)
un  nginx          <none>             <none>       (no description available)
ii  nginx-common   1.24.0-2ubuntu7.18 all          small, powerful, scalable web/proxy server - common files
# ... (trimmed)
0 upgraded, 0 newly installed, 0 to remove and 51 not upgraded.

Removing nginx left nginx-common and its configuration in place. policy-rc.d on this playground blocks services from starting during package installation; on a normal Ubuntu server, installing nginx starts it immediately.

Debian packages start services on install

Ubuntu enables and starts most daemons when they are installed, before any configuration is reviewed. RHEL installs them disabled. Configure or mask a service before installing it on an exposed host.

Task Command
Install a local .deb with dependencies sudo apt install ./pkg.deb
Reinstall sudo apt install --reinstall <pkg>
Upgrade installed packages sudo apt update && sudo apt upgrade
Upgrade, allowing new or removed dependencies sudo apt full-upgrade
Simulate apt-get -s install <pkg>
Download and inspect a .deb apt-get download <pkg>, dpkg -c, dpkg -I
Fix an interrupted install sudo dpkg --configure -a, then sudo apt -f install

Holds, Updates and History

sudo apt-mark hold bash
apt-mark showhold
sudo apt-mark unhold bash
apt list --upgradable 2>/dev/null | head -4
tail -5 /var/log/apt/history.log

Output:

bash set on hold.
bash
Canceled hold on bash.
Listing...
base-files/noble-updates 13ubuntu10.5 amd64 [upgradable from: 13ubuntu10.4]
bind9-dnsutils/noble-updates,noble-security 1:9.18.39-0ubuntu0.24.04.7 amd64 [upgradable from: 1:9.18.39-0ubuntu0.24.04.6]
bind9-host/noble-updates,noble-security 1:9.18.39-0ubuntu0.24.04.7 amd64 [upgradable from: 1:9.18.39-0ubuntu0.24.04.6]
Start-Date: 2026-09-16  14:42:59
Commandline: apt-get purge -y nginx-common
Requested-By: laborant (1001)
Purge: nginx-common:amd64 (1.24.0-2ubuntu7.18)
End-Date: 2026-09-16  14:43:00

apt has no undo

apt has no undo; the history log shows what changed, and a specific version is reinstalled with apt install <pkg>=<version>. Unattended security updates come from the unattended-upgrades package.


Common Errors

sudo apt-get install -y nosuchpackage

Output:

Reading state information...
E: Unable to locate package nosuchpackage

E: Unable to locate package nosuchpackage

Cause: the package lists are stale (apt update never ran on a fresh image), the name is wrong, or the component (universe) or repository is missing.

Fix: sudo apt update, then apt-cache search <name> or apt-file search.

While another process holds the dpkg lock (here a Python process standing in for unattended-upgrades), apt-get fails at once and apt waits:

sudo apt-get install -y sl
sudo apt install -y sl

Output:

E: Could not get lock /var/lib/dpkg/lock-frontend. It is held by process 5162 (python3)
E: Unable to acquire the dpkg frontend lock (/var/lib/dpkg/lock-frontend), is another process using it?
Waiting for cache lock: Could not get lock /var/lib/dpkg/lock-frontend. It is held by process 5162 (python3)...

E: Could not get lock /var/lib/dpkg/lock-frontend. It is held by process 5162 (python3)

Cause: another package operation is running, often unattended-upgrades right after boot.

Fix: check the named process and wait; apt-get -o DPkg::Lock::Timeout=300 waits in scripts. Never delete the lock files while a process holds them.

E: dpkg was interrupted, you must manually run 'sudo dpkg --configure -a' to correct the problem.

Cause: a previous install stopped halfway and left entries in /var/lib/dpkg/updates/.

Fix: sudo dpkg --configure -a, then sudo apt -f install.


Interview Checkpoints

L1: What is the difference between apt remove and apt purge?

Say first: remove deletes the program but keeps its configuration files; purge deletes both.

Proof: after remove, dpkg -l shows rc or leaves the -common package with its config.

Follow-up: How do you list every package in the rc state? (dpkg -l | grep '^rc'.)

L1: Why does apt install say Unable to locate package on a fresh cloud image?

Say first: the package index is empty or stale until apt update runs.

Proof: sudo apt update && sudo apt install nginx succeeds.

Follow-up: Why do Dockerfiles combine apt-get update and install in one RUN?

L2: Find which package provides a command that is not installed.

Say first: search the file index.

Proof: sudo apt install apt-file && sudo apt-file update && apt-file search -x '/usr/bin/dig$'

Follow-up: What is the RHEL equivalent?

L2: Keep Docker at its current version during system upgrades.

Say first: hold the packages.

Proof: sudo apt-mark hold docker-ce docker-ce-cli containerd.io; apt-mark showhold

Follow-up: What risk does a long-term hold create?

L2: Show where a package would be installed from and which versions exist.

Say first: apt-cache policy lists candidates with priorities and repositories.

Proof: apt-cache policy nginx

Follow-up: How do you install a specific version? (apt install nginx=<version>.)

L3: apt fails with Could not get lock right after a server boots.

Say first: check which process holds the lock before touching anything.

Proof: sudo lsof /var/lib/dpkg/lock-frontend or ps -ef | grep unattended shows unattended-upgrades running.

Follow-up: How do provisioning scripts wait for it safely? (systemd-run --wait or loop on fuser.)

L3: After an interrupted upgrade, every apt command fails.

Say first: finish the half-configured packages first.

Proof: dpkg -l | grep -E '^i[UF]' lists them; sudo dpkg --configure -a then sudo apt -f install.

Follow-up: Where do you find what the interrupted upgrade was doing? (/var/log/apt/term.log.)


Captured on Rocky Linux 10.2 and Ubuntu 24.04.4 LTS (iximiuz Labs microVMs, kernel 6.1.167), 2026-09.