When managing production Ubuntu/Debian systems, you often encounter situations where certain packages must remain at specific versions. This could be due to:
- Compatibility requirements with legacy systems
- Stability concerns with newer versions
- Enterprise software certification requirements
Ubuntu/Debian's APT package manager provides a simple yet effective way to freeze package versions:
sudo apt-mark hold package_name
For example, to hold the Puppet package at version 2.7.19:
sudo apt-mark hold puppet
sudo apt-mark hold puppet-server
To check which packages are currently held:
apt-mark showhold
Sample output:
puppet
puppet-server
For more granular control, you can create pinning rules:
Package: puppet
Pin: version 2.7.19-1
Pin-Priority: 1001
Package: puppet-server
Pin: version 2.7.19-1
Pin-Priority: 1001
When holding packages, watch for dependencies:
apt-cache depends package_name
To allow upgrades again:
sudo apt-mark unhold package_name
Here's a bash script to automate version locking:
#!/bin/bash
PACKAGES=("puppet" "puppet-server")
VERSIONS=("2.7.19-1" "2.7.19-1")
for i in "${!PACKAGES[@]}"; do
sudo apt-mark hold "${PACKAGES[$i]}=${VERSIONS[$i]}"
done
- Document all held packages in your system documentation
- Regularly review held packages for security implications
- Consider using containers for legacy version requirements
When managing production servers, unexpected package upgrades can break compatibility. In the Puppet ecosystem, for example, version 3.0 introduced breaking changes that weren't backward compatible with 2.7.x configurations. Similar scenarios occur with database systems, programming language runtimes, and other critical infrastructure.
Ubuntu/Debian's APT system provides two powerful mechanisms to control package versions:
# Method 1: Using apt-mark
sudo apt-mark hold package_name
# Method 2: Pinning via /etc/apt/preferences.d/
Package: puppet
Pin: version 2.7.19-1
Pin-Priority: 1001
For permanent version locking, the preferences file approach is more robust. Here's how to implement it:
# Create a new pinning file
sudo nano /etc/apt/preferences.d/puppet-hold
# Add these contents (example for Puppet):
Package: puppet
Pin: version 2.7.19-1*
Pin-Priority: 1001
Package: puppet-server
Pin: version 2.7.19-1*
Pin-Priority: 1001
After setting up pinning, verify it works before running upgrades:
# Check hold status
apt-mark showhold
# Simulate upgrade
apt-get -s upgrade
# Check policy
apt-cache policy puppet
For complex scenarios, you can use multiple pinning criteria:
Package: *
Pin: release o=MyCompany
Pin-Priority: 900
Package: *
Pin: release a=stable
Pin-Priority: 800
Watch out for these issues:
- Dependencies might still pull newer versions (use
Pin-Priority: 1001
to override) - Security updates might be blocked (consider creating exceptions)
- Multiple pin files can conflict (use
apt-cache policy
to debug)
For manual version control:
# Download specific version
apt-get download package=version
# Install with forced downgrade
sudo dpkg --force-downgrade -i package.deb