Debian Server Package Management: Complete Administrator's Guide
Debian's package management system is one of the most sophisticated and reliable in the Linux world. This comprehensive guide covers everything from basic package operations to advanced repository management and custom package creation.
Understanding Debian Package Management
Debian uses a two-tier package management system: - dpkg: Low-level package tool that handles individual .deb files - APT: Advanced Package Tool that manages dependencies and repositories
Package Management Architecture
APT (User Interface)
├── apt-get / apt
├── aptitude
└── synaptic
|
Repository Management
|
dpkg (Core Tool)
|
.deb Package Files
APT: Advanced Package Tool
Basic APT Operations
# Update package database
sudo apt update
# Upgrade all packages
sudo apt upgrade
# Full system upgrade (handles dependencies changes)
sudo apt full-upgrade
# Install packages
sudo apt install nginx php-fpm mysql-server
# Remove packages (keep config files)
sudo apt remove apache2
# Purge packages (remove everything)
sudo apt purge apache2
# Search for packages
apt search "web server"
apt search --names-only nginx
# Show package information
apt show nginx
# List installed packages
apt list --installed
# List upgradable packages
apt list --upgradable
# Clean package cache
sudo apt clean
sudo apt autoclean
# Remove unnecessary dependencies
sudo apt autoremove
APT Configuration
# Main APT configuration file
cat > /etc/apt/apt.conf.d/99custom << 'EOF'
# Custom APT Configuration
# Download settings
Acquire::http::Timeout "30";
Acquire::https::Timeout "30";
Acquire::ftp::Timeout "30";
Acquire::Retries "3";
# Cache settings
Dir::Cache::archives "/var/cache/apt/archives";
APT::Clean-Installed "false";
# Automatic updates
APT::Periodic::Update-Package-Lists "1";
APT::Periodic::Download-Upgradeable-Packages "1";
APT::Periodic::AutocleanInterval "7";
APT::Periodic::Unattended-Upgrade "1";
# Default release
APT::Default-Release "stable";
# Compression
Acquire::CompressionTypes::Order "gz";
# Language
Acquire::Languages "none";
# Assume yes for automation
# APT::Get::Assume-Yes "true";
# Show versions
APT::Get::Show-Versions "true";
EOF
# Configure proxy for APT
cat > /etc/apt/apt.conf.d/95proxy << 'EOF'
Acquire::http::Proxy "http://proxy.company.com:8080";
Acquire::https::Proxy "http://proxy.company.com:8080";
Acquire::ftp::Proxy "http://proxy.company.com:8080";
EOF
APT Preferences and Pinning
# Create preferences file for package pinning
cat > /etc/apt/preferences.d/nginx << 'EOF'
# Pin nginx from backports
Package: nginx
Pin: release a=bullseye-backports
Pin-Priority: 900
# Prevent postgresql from updating
Package: postgresql*
Pin: version 13.*
Pin-Priority: 1001
# Prefer packages from stable
Package: *
Pin: release a=stable
Pin-Priority: 500
# Lower priority for testing
Package: *
Pin: release a=testing
Pin-Priority: 100
EOF
# Check package priorities
apt-cache policy nginx
# Simulate installation to check what will be installed
apt install -s nginx
Repository Management
Sources List Configuration
# Main sources.list for Debian 11 (Bullseye)
cat > /etc/apt/sources.list << 'EOF'
# Main repository
deb http://deb.debian.org/debian/ bullseye main contrib non-free
deb-src http://deb.debian.org/debian/ bullseye main contrib non-free
# Security updates
deb http://security.debian.org/debian-security bullseye-security main contrib non-free
deb-src http://security.debian.org/debian-security bullseye-security main contrib non-free
# System updates
deb http://deb.debian.org/debian/ bullseye-updates main contrib non-free
deb-src http://deb.debian.org/debian/ bullseye-updates main contrib non-free
# Backports
deb http://deb.debian.org/debian/ bullseye-backports main contrib non-free
deb-src http://deb.debian.org/debian/ bullseye-backports main contrib non-free
EOF
# Add third-party repository example (Docker)
# Install prerequisites
sudo apt install apt-transport-https ca-certificates curl gnupg lsb-release
# Add Docker GPG key
curl -fsSL https://download.docker.com/linux/debian/gpg | sudo gpg --dearmor -o /usr/share/keyrings/docker-archive-keyring.gpg
# Add Docker repository
echo "deb [arch=$(dpkg --print-architecture) signed-by=/usr/share/keyrings/docker-archive-keyring.gpg] https://download.docker.com/linux/debian $(lsb_release -cs) stable" | sudo tee /etc/apt/sources.list.d/docker.list > /dev/null
# Update package database
sudo apt update
Mirror Management
#!/bin/bash
# Script to find and set fastest Debian mirror
# Install netselect-apt
apt install netselect-apt
# Find fastest mirror
netselect-apt -c US -t 20 -a amd64 stable
# Backup current sources.list
cp /etc/apt/sources.list /etc/apt/sources.list.backup
# Use mirror list
cat > /etc/apt/sources.list << 'EOF'
# Fastest mirrors for United States
deb http://mirror.steadfast.net/debian/ bullseye main contrib non-free
deb-src http://mirror.steadfast.net/debian/ bullseye main contrib non-free
deb http://mirror.steadfast.net/debian/ bullseye-updates main contrib non-free
deb-src http://mirror.steadfast.net/debian/ bullseye-updates main contrib non-free
deb http://security.debian.org/debian-security bullseye-security main contrib non-free
deb-src http://security.debian.org/debian-security bullseye-security main contrib non-free
EOF
# Create local mirror (for multiple servers)
apt install apt-mirror
# Configure apt-mirror
cat > /etc/apt/mirror.list << 'EOF'
set base_path /var/spool/apt-mirror
set nthreads 20
set _tilde 0
# Debian 11 repositories
deb-amd64 http://deb.debian.org/debian bullseye main contrib non-free
deb-amd64 http://deb.debian.org/debian bullseye-updates main contrib non-free
deb-amd64 http://security.debian.org/debian-security bullseye-security main contrib non-free
clean http://deb.debian.org/debian
EOF
# Run mirror sync
apt-mirror
dpkg: Low-Level Package Management
dpkg Operations
# Install a .deb package
sudo dpkg -i package.deb
# Remove a package
sudo dpkg -r package-name
# Purge a package (remove with config files)
sudo dpkg -P package-name
# List installed packages
dpkg -l
dpkg -l | grep nginx
# List files in a package
dpkg -L nginx
# Find which package owns a file
dpkg -S /usr/sbin/nginx
# Show package information
dpkg -s nginx
# Extract package without installing
dpkg -x package.deb /tmp/extracted/
# Extract control information
dpkg -e package.deb /tmp/control/
# Reconfigure a package
sudo dpkg-reconfigure tzdata
# Fix broken dependencies
sudo apt --fix-broken install
# Clear package selections
sudo dpkg --clear-selections
# Set package selections from file
sudo dpkg --set-selections < selections.txt
# Get current selections
dpkg --get-selections > selections.txt
Package Database Management
# Backup dpkg database
tar czf dpkg-backup-$(date +%Y%m%d).tar.gz /var/lib/dpkg
# Check database consistency
sudo dpkg --audit
# Clear available file
sudo dpkg --clear-avail
# Update available file
sudo apt-cache dumpavail | sudo dpkg --update-avail
# Rebuild package database
sudo dpkg --configure -a
# Force remove broken package
sudo dpkg --remove --force-remove-reinstreq package-name
# Lock/unlock packages
echo "nginx hold" | sudo dpkg --set-selections
echo "nginx install" | sudo dpkg --set-selections
Package Building and Management
Creating Debian Packages
# Install packaging tools
sudo apt install build-essential devscripts debhelper dh-make
# Create package structure
mkdir -p myapp-1.0/{DEBIAN,usr/bin,usr/share/doc/myapp}
# Create control file
cat > myapp-1.0/DEBIAN/control << 'EOF'
Package: myapp
Version: 1.0-1
Section: utils
Priority: optional
Architecture: amd64
Depends: libc6 (>= 2.31), python3 (>= 3.9)
Maintainer: Your Name <you@example.com>
Description: My Application
This is a longer description of my application.
It can span multiple lines.
.
Each paragraph is separated by a line with a single dot.
EOF
# Create postinst script
cat > myapp-1.0/DEBIAN/postinst << 'EOF'
#!/bin/bash
set -e
case "$1" in
configure)
# Create user for application
if ! getent passwd myapp >/dev/null; then
adduser --system --group --home /var/lib/myapp myapp
fi
# Set permissions
chown -R myapp:myapp /var/lib/myapp
# Start service
systemctl enable myapp.service
systemctl start myapp.service
;;
abort-upgrade|abort-remove|abort-deconfigure)
;;
*)
echo "postinst called with unknown argument '$1'" >&2
exit 1
;;
esac
exit 0
EOF
chmod 755 myapp-1.0/DEBIAN/postinst
# Build the package
dpkg-deb --build myapp-1.0
# Check package
lintian myapp-1.0.deb
# Advanced package building with debhelper
cd myapp-1.0
dh_make --native --single --packagename myapp_1.0 --email you@example.com
# Edit debian/control
cat > debian/control << 'EOF'
Source: myapp
Section: utils
Priority: optional
Maintainer: Your Name <you@example.com>
Build-Depends: debhelper-compat (= 13), python3-dev
Standards-Version: 4.5.1
Homepage: https://example.com/myapp
Package: myapp
Architecture: any
Depends: ${shlibs:Depends}, ${misc:Depends}, python3
Description: My Application
This is my application package.
It does wonderful things.
EOF
# Build package
dpkg-buildpackage -us -uc
Local Repository Creation
# Install repository tools
sudo apt install reprepro gnupg
# Create repository structure
mkdir -p /var/local/repo/{conf,dists,pool}
cd /var/local/repo
# Generate GPG key for signing
gpg --gen-key
# Export public key
gpg --armor --export you@example.com > repository.key
# Create distributions file
cat > conf/distributions << 'EOF'
Origin: My Local Repository
Label: My Local Repository
Codename: bullseye
Architectures: amd64 source
Components: main
Description: My local Debian repository
SignWith: you@example.com
EOF
# Add package to repository
reprepro includedeb bullseye /path/to/package.deb
# Update repository
reprepro export
# Configure web server for repository
cat > /etc/nginx/sites-available/repo << 'EOF'
server {
listen 80;
server_name repo.local;
root /var/local/repo;
location / {
autoindex on;
}
location ~ /(db|conf) {
deny all;
}
}
EOF
# Enable site
ln -s /etc/nginx/sites-available/repo /etc/nginx/sites-enabled/
nginx -t && systemctl reload nginx
# Add repository to clients
echo "deb [signed-by=/usr/share/keyrings/myrepo.gpg] http://repo.local/ bullseye main" > /etc/apt/sources.list.d/local.list
wget -O- http://repo.local/repository.key | gpg --dearmor > /usr/share/keyrings/myrepo.gpg
apt update
Dependency Management
Resolving Dependencies
# Check package dependencies
apt-cache depends nginx
# Check reverse dependencies
apt-cache rdepends nginx
# Show dependency tree
apt install apt-rdepends
apt-rdepends nginx
# Simulate installation to see dependencies
apt install -s package-name
# Fix broken dependencies
sudo apt --fix-broken install
# Force install ignoring dependencies (dangerous!)
sudo dpkg --force-depends -i package.deb
# Hold packages at current version
sudo apt-mark hold nginx
sudo apt-mark unhold nginx
# Show held packages
apt-mark showhold
# Mark package as manually installed
sudo apt-mark manual package-name
# Mark package as automatically installed
sudo apt-mark auto package-name
# Show manually installed packages
apt-mark showmanual
Conflict Resolution
#!/bin/bash
# Script to help resolve package conflicts
# Function to check conflicts
check_conflicts() {
local package=$1
echo "Checking conflicts for $package..."
# Get conflicts
conflicts=$(apt-cache show $package | grep -E "^Conflicts:" | cut -d: -f2-)
if [ -n "$conflicts" ]; then
echo "Conflicts found: $conflicts"
# Check if conflicting packages are installed
for conflict in $conflicts; do
if dpkg -l | grep -q "^ii.*$conflict"; then
echo "WARNING: Conflicting package $conflict is installed"
fi
done
else
echo "No conflicts found"
fi
}
# Function to resolve file conflicts
resolve_file_conflicts() {
local package=$1
# Get list of files
files=$(dpkg -L $package 2>/dev/null)
if [ $? -eq 0 ]; then
for file in $files; do
# Check if file exists in another package
owner=$(dpkg -S $file 2>/dev/null | grep -v "^$package:" | cut -d: -f1)
if [ -n "$owner" ]; then
echo "File conflict: $file is owned by $owner"
fi
done
fi
}
# Main script
if [ $# -eq 0 ]; then
echo "Usage: $0 <package-name>"
exit 1
fi
check_conflicts $1
resolve_file_conflicts $1
Automated Updates and Maintenance
Unattended Upgrades
# Install unattended-upgrades
sudo apt install unattended-upgrades apt-listchanges
# Configure unattended-upgrades
cat > /etc/apt/apt.conf.d/50unattended-upgrades << 'EOF'
// Automatically upgrade packages from these origins
Unattended-Upgrade::Origins-Pattern {
"origin=Debian,codename=${distro_codename},label=Debian";
"origin=Debian,codename=${distro_codename},label=Debian-Security";
"origin=Debian,codename=${distro_codename}-security,label=Debian-Security";
"origin=Debian,codename=${distro_codename}-updates";
};
// List of packages to not update
Unattended-Upgrade::Package-Blacklist {
"nginx";
"mysql-server";
"postgresql";
};
// Remove unused automatically installed kernel-related packages
Unattended-Upgrade::Remove-Unused-Kernel-Packages "true";
// Do automatic removal of newly unused dependencies
Unattended-Upgrade::Remove-New-Unused-Dependencies "true";
// Do automatic removal of unused packages
Unattended-Upgrade::Remove-Unused-Dependencies "true";
// Automatically reboot WITHOUT CONFIRMATION
Unattended-Upgrade::Automatic-Reboot "true";
// Automatically reboot even if users are logged in
Unattended-Upgrade::Automatic-Reboot-WithUsers "false";
// If automatic reboot is enabled and needed, reboot at the specific time
Unattended-Upgrade::Automatic-Reboot-Time "03:00";
// Enable upgrade reports via email
Unattended-Upgrade::Mail "admin@example.com";
// Set this value to one of:
// "always", "only-on-error" or "on-change"
Unattended-Upgrade::MailReport "only-on-error";
// Log to syslog
Unattended-Upgrade::SyslogEnable "true";
EOF
# Enable automatic updates
cat > /etc/apt/apt.conf.d/20auto-upgrades << 'EOF'
APT::Periodic::Update-Package-Lists "1";
APT::Periodic::Download-Upgradeable-Packages "1";
APT::Periodic::AutocleanInterval "7";
APT::Periodic::Unattended-Upgrade "1";
EOF
# Test unattended-upgrades
sudo unattended-upgrade --debug --dry-run
Package Maintenance Scripts
#!/bin/bash
# Comprehensive package maintenance script
# Log file
LOG_FILE="/var/log/package-maintenance.log"
# Function to log messages
log_message() {
echo "[$(date '+%Y-%m-%d %H:%M:%S')] $1" | tee -a "$LOG_FILE"
}
# Update package lists
log_message "Updating package lists..."
apt update 2>&1 | tee -a "$LOG_FILE"
# Check for upgradable packages
log_message "Checking for upgradable packages..."
upgradable=$(apt list --upgradable 2>/dev/null | grep -v "Listing" | wc -l)
if [ $upgradable -gt 0 ]; then
log_message "Found $upgradable upgradable packages"
apt list --upgradable 2>/dev/null | tee -a "$LOG_FILE"
# Perform upgrade
log_message "Performing system upgrade..."
DEBIAN_FRONTEND=noninteractive apt upgrade -y 2>&1 | tee -a "$LOG_FILE"
else
log_message "System is up to date"
fi
# Clean up
log_message "Cleaning package cache..."
apt clean
apt autoclean
apt autoremove -y 2>&1 | tee -a "$LOG_FILE"
# Check for broken packages
log_message "Checking for broken packages..."
broken=$(dpkg -l | grep -E "^[^i]" | wc -l)
if [ $broken -gt 0 ]; then
log_message "Found $broken broken packages, attempting to fix..."
apt --fix-broken install -y 2>&1 | tee -a "$LOG_FILE"
dpkg --configure -a 2>&1 | tee -a "$LOG_FILE"
fi
# Check disk space
log_message "Checking disk space..."
df -h | grep -E "^/dev/" | while read line; do
usage=$(echo $line | awk '{print $5}' | sed 's/%//')
filesystem=$(echo $line | awk '{print $1}')
if [ $usage -gt 90 ]; then
log_message "WARNING: $filesystem is $usage% full"
fi
done
# Generate package report
log_message "Generating package report..."
cat > /var/log/package-report-$(date +%Y%m%d).txt << EOF
Package Report - $(date)
========================
Total installed packages: $(dpkg -l | grep "^ii" | wc -l)
Held packages: $(apt-mark showhold | wc -l)
Manually installed: $(apt-mark showmanual | wc -l)
Auto-installed: $(apt-mark showauto | wc -l)
Recently installed packages:
$(grep " install " /var/log/dpkg.log | tail -20)
Recently removed packages:
$(grep " remove " /var/log/dpkg.log | tail -10)
Package cache size: $(du -sh /var/cache/apt/archives | cut -f1)
EOF
log_message "Maintenance completed"
Security Considerations
Package Verification
# Check package signatures
apt-key list
# Verify package integrity
debsums -c
debsums nginx
# Install debsums for all packages
apt install debsums
debsums -g
# Verify specific package files
dpkg -V nginx
# Check for packages without verification
dpkg -l | grep "^ii" | awk '{print $2}' | while read pkg; do
if ! dpkg -V $pkg >/dev/null 2>&1; then
echo "Cannot verify: $pkg"
fi
done
# Audit installed packages for security issues
apt install debsecan
debsecan
# Check for obsolete packages
apt install debian-goodies
checkrestart
APT Security Configuration
# Secure APT configuration
cat > /etc/apt/apt.conf.d/99security << 'EOF'
// Verify package signatures
APT::Get::AllowUnauthenticated "false";
// Use HTTPS for repositories where possible
Acquire::https::Verify-Peer "true";
Acquire::https::Verify-Host "true";
// Sandbox downloaded files
APT::Sandbox::User "_apt";
// Limit concurrent connections
Acquire::http::Pipeline-Depth "0";
Acquire::http::No-Cache "true";
Acquire::BrokenProxy "true";
// Security options
Acquire::Check-Valid-Until "true";
APT::Get::List-Cleanup "true";
EOF
# Configure apt-listbugs for security notifications
apt install apt-listbugs
Troubleshooting Package Issues
Common Problems and Solutions
#!/bin/bash
# Package troubleshooting toolkit
# Function to fix common dpkg errors
fix_dpkg_errors() {
echo "Fixing dpkg errors..."
# Fix lock files
sudo rm -f /var/lib/dpkg/lock-frontend
sudo rm -f /var/lib/dpkg/lock
sudo rm -f /var/cache/apt/archives/lock
# Reconfigure dpkg
sudo dpkg --configure -a
# Fix broken packages
sudo apt --fix-broken install
}
# Function to rebuild package database
rebuild_package_db() {
echo "Rebuilding package database..."
# Backup current status
sudo cp /var/lib/dpkg/status /var/lib/dpkg/status.backup
# Clear and rebuild
sudo apt clean
sudo apt update
sudo apt-cache gencaches
}
# Function to resolve held packages
resolve_held_packages() {
echo "Checking for held packages..."
held=$(apt-mark showhold)
if [ -n "$held" ]; then
echo "Found held packages:"
echo "$held"
echo "Do you want to unhold these packages? (y/n)"
read answer
if [ "$answer" = "y" ]; then
echo "$held" | xargs sudo apt-mark unhold
fi
fi
}
# Function to clean package system
deep_clean() {
echo "Performing deep clean..."
# Remove package cache
sudo apt clean
# Remove old config files
dpkg -l | grep "^rc" | awk '{print $2}' | xargs sudo dpkg --purge
# Remove orphaned packages
sudo apt autoremove --purge
# Clean apt lists
sudo rm -rf /var/lib/apt/lists/*
sudo apt update
}
# Main menu
echo "Package Troubleshooting Toolkit"
echo "1. Fix dpkg errors"
echo "2. Rebuild package database"
echo "3. Resolve held packages"
echo "4. Deep clean system"
echo "5. Exit"
read -p "Select option: " option
case $option in
1) fix_dpkg_errors ;;
2) rebuild_package_db ;;
3) resolve_held_packages ;;
4) deep_clean ;;
5) exit 0 ;;
*) echo "Invalid option" ;;
esac
Best Practices
Package Management Guidelines
- Always Update Package Lists: Run
apt update
before installing or upgrading - Use Simulation: Test changes with
-s
flag before applying - Keep System Clean: Regularly run
apt autoremove
andapt clean
- Document Changes: Keep a log of package installations and removals
- Backup Before Major Changes: Create system snapshots before upgrades
- Monitor Security Updates: Subscribe to debian-security-announce
- Test in Staging: Test package updates in non-production first
- Use Configuration Management: Consider tools like Ansible for consistency
Maintenance Schedule
# Create maintenance cron jobs
cat > /etc/cron.d/apt-maintenance << 'EOF'
# Update package lists daily
0 1 * * * root /usr/bin/apt update >/dev/null 2>&1
# Clean package cache weekly
0 2 * * 0 root /usr/bin/apt clean >/dev/null 2>&1
# Remove unused packages weekly
0 3 * * 0 root /usr/bin/apt autoremove -y >/dev/null 2>&1
# Security updates check daily
0 4 * * * root /usr/bin/apt list --upgradable 2>/dev/null | grep -i security | mail -E -s "Security Updates Available" admin@example.com
EOF
Conclusion
Debian's package management system provides powerful tools for maintaining a stable and secure server environment. Understanding both APT and dpkg, along with proper repository management and maintenance practices, ensures reliable system administration.
Next Steps
- Explore advanced APT features like apt-patterns
- Learn about Debian packaging for software distribution
- Implement automated testing for package updates
- Study Debian policy for package maintenance
- Consider contributing to Debian package maintenance
Remember: Good package management is the foundation of a stable Debian system. Take time to understand the tools and establish proper procedures for your environment.