Debian Server Package Management: Complete Administrator's Guide

Tyler Maginnis | February 07, 2024

DebianLinuxpackage managementAPTdpkg

Need Professional Debian Server Support?

Get expert assistance with your debian server support implementation and management. Tyler on Tech Louisville provides priority support for Louisville businesses.

Same-day service available for Louisville area

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

  1. Always Update Package Lists: Run apt update before installing or upgrading
  2. Use Simulation: Test changes with -s flag before applying
  3. Keep System Clean: Regularly run apt autoremove and apt clean
  4. Document Changes: Keep a log of package installations and removals
  5. Backup Before Major Changes: Create system snapshots before upgrades
  6. Monitor Security Updates: Subscribe to debian-security-announce
  7. Test in Staging: Test package updates in non-production first
  8. 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.