When maintaining a private APT repository for Ubuntu (especially legacy systems like 10.04), a common requirement is enabling simultaneous access to multiple versions of the same package. This is particularly crucial for QA workflows where testers might need to validate builds against specific historical versions.
By design, standard APT repositories typically host only the latest version of a package in each distribution component. When you run apt-get install package
, the system automatically selects the highest available version number.
Example of standard repository structure:
deb http://repo.example.com/ubuntu lucid main
The most robust approach involves creating separate repository distributions for each major version:
# /etc/apt/sources.list.d/private-repo.list deb http://repo.example.com/ubuntu lucid-1.0 main deb http://repo.example.com/ubuntu lucid-1.1 main deb http://repo.example.com/ubuntu lucid-2.0 main
Then use pinning in /etc/apt/preferences.d/private-repo
:
Package: your-package Pin: release n=lucid-1.0 Pin-Priority: 1001 Package: your-package Pin: release n=lucid-1.1 Pin-Priority: 1000
For simpler cases, you can include version numbers directly in package names:
# Control file example Package: your-package-1.0 Version: 1.0-1 Depends: your-package-common (= 1.0-1) Package: your-package-2.0 Version: 2.0-1 Depends: your-package-common (= 2.0-1)
When implementing this, consider using:
reprepro
with multiple codename distributionsaptly
with snapshot functionality- Custom scripts with
dput
anddpkg-scanpackages
Here's how to create multiple distributions with reprepro:
# conf/distributions Origin: Your Company Label: Private Repo Codename: lucid-1.0 Architectures: i386 amd64 Components: main Description: Version 1.0 packages Codename: lucid-1.1 Architectures: i386 amd64 Components: main Description: Version 1.1 packages
Then install specific versions with:
apt-get install your-package=1.0-1
When maintaining Ubuntu 10.04 systems across an enterprise environment, the need to support multiple versions of internal applications becomes critical - particularly for QA teams requiring version-specific testing capabilities. The standard APT repository structure doesn't natively support parallel version installation through the same distribution channel.
APT repositories typically follow a simple versioning model where only the highest-numbered package version is installable from a given distribution component. Attempting to host multiple versions of myapp_1.0.deb
and myapp_1.1.deb
in the same main
distribution will result in package conflicts during updates.
Here are three proven approaches to implement version-flexible repositories:
1. Distribution-Based Version Isolation
Create separate distribution entries for each version in your dists
directory:
dists/ └── myapp/ ├── 1.0/ │ ├── main/ │ │ └── binary-amd64/ │ └── Release └── 1.1/ ├── main/ │ └── binary-amd64/ └── Release
Configure sources.list entries with explicit version pins:
deb [arch=amd64] http://repo.example.com/ubuntu myapp/1.0 main deb [arch=amd64] http://repo.example.com/ubuntu myapp/1.1 main
2. Virtual Package Names
Rename packages to include version identifiers in the package name itself:
myapp-1.0_1.0-1_amd64.deb myapp-1.1_1.1-1_amd64.deb
Control installation through meta-packages or direct specification:
apt-get install myapp-1.0
3. Snapshot Repositories
Implement timestamped repository snapshots using tools like aptly:
aptly snapshot create myapp-20230101 from mirror myapp-prod aptly publish snapshot myapp-20230101
For precise control, combine repository separation with APT pinning:
Package: myapp Pin: release n=myapp-1.0 Pin-Priority: 1001
Example configuration for multiple version support in reprepro:
Codename: precise-myapp-1.0 Architectures: amd64 i386 Components: main Description: MyApp 1.0 packages
When hosting multiple versions:
- Maintain separate GPG keys per major version
- Implement repository signing for each distribution
- Set appropriate ACLs for version-specific uploads
Sample Jenkins pipeline snippet for versioned deployments:
pipeline { stages { stage('Package') { steps { sh 'dpkg-buildpackage -us -uc' sh 'mv ../myapp_${VERSION}_amd64.deb /repo/pool/${VERSION}/' } } } }