How to Preserve Existing Config Files During apt-get Installations in Debian/Ubuntu


1 views

When managing servers, we often face a common dilemma: how to install new packages while preserving our carefully crafted configuration files. The default apt-get install behavior typically prompts users about conflicting config files, which isn't ideal for automated deployments.

The solution lies in dpkg's configuration options. Here are the key parameters:


# For non-interactive preservation:
DEBIAN_FRONTEND=noninteractive apt-get -o Dpkg::Options::="--force-confold" install -y mysql-server

# Alternative approach using configuration:
echo 'Dpkg::Options {
   "--force-confdef";
   "--force-confold";
}' > /etc/apt/apt.conf.d/local
  • --force-confdef: Use the default option automatically when available
  • --force-confold: Keep the old version of configuration files
  • --force-confnew: Use the new maintainer version (opposite of what we want)

Here's how I handle MySQL server upgrades while preserving my custom my.cnf:


#!/bin/bash
export DEBIAN_FRONTEND=noninteractive
apt-get update
apt-get -y -o Dpkg::Options::="--force-confold" install mysql-server-8.0

It's important to understand the three possible states of configuration files during package installation:

State Description Behavior with --force-confold
Unmodified Original package version Will be upgraded
Modified Changed by admin Preserved
New in package Previously non-existent Created

For granular control, you can specify different behaviors for different packages:


# /etc/apt/apt.conf.d/51keepconfigs
Dpkg::Options {
   // Keep all PHP configs
   "php*::--force-confold";
   
   // Use defaults for nginx but keep existing
   "nginx::--force-confdef";
   "nginx::--force-confold";
};

If you encounter issues:

  1. Check /var/lib/dpkg/status for package configuration states
  2. Use dpkg --audit to identify configuration problems
  3. View kept-back files with dpkg --status package-name

For production environments, consider managing configurations separately:


# Example Ansible playbook snippet
- name: Install MySQL while preserving configs
  apt:
    name: mysql-server
    state: present
    dpkg_options: 'force-confold,force-confdef'

Every sysadmin knows that moment of hesitation when running apt-get install on a system with existing configurations. The default behavior typically presents an interactive prompt asking whether to:

  • Keep the existing config file
  • Install the maintainer's version
  • Show differences

For automated deployments and CI/CD pipelines, we need deterministic behavior. Here are the technical approaches:

# Solution 1: Using debconf preseed
echo "mysql-server mysql-server/root_password password temp_pw" | debconf-set-selections
echo "mysql-server mysql-server/root_password_again password temp_pw" | debconf-set-selections
DEBIAN_FRONTEND=noninteractive apt-get -y install mysql-server

# Solution 2: Using dpkg options
apt-get -o Dpkg::Options::="--force-confold" install mysql-server

# Solution 3: Combining both approaches
DEBIAN_FRONTEND=noninteractive apt-get -o Dpkg::Options::="--force-confold" -y install mysql-server

The --force-confold option tells dpkg to:

  • Keep modified configuration files
  • Only overwrite if the file hasn't been changed from default
  • Never prompt during installation

Here's how we implemented this in an Ansible playbook for MySQL configuration:

- name: Install MySQL preserving existing config
  apt:
    name: mysql-server
    state: present
    dpkg_options: 'force-confold'
  environment:
    DEBIAN_FRONTEND: noninteractive

After installation, verify config file status with:

# Check which files would be replaced
sudo apt-get -o Dpkg::Options::="--force-confnew" install --reinstall -s mysql-server

# View actual config file status
sudo dpkg-query -W -f='${Conffiles}\n' mysql-server | awk '{print $2}' | xargs -I{} ls -la {}

For more complex scenarios, consider separating config management from package installation:

# First install package with default configs
DEBIAN_FRONTEND=noninteractive apt-get -y install mysql-server

# Then apply your custom configurations
sudo cp /path/to/your/my.cnf /etc/mysql/my.cnf
sudo systemctl restart mysql