How to Permanently Block Package Updates in Ubuntu/Debian Using APT Hold Mechanism


3 views

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