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:
- Check
/var/lib/dpkg/status
for package configuration states - Use
dpkg --audit
to identify configuration problems - 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