How to Host Multiple Versions of the Same Package in a Private APT Repository for Ubuntu


1 views

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 distributions
  • aptly with snapshot functionality
  • Custom scripts with dput and dpkg-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}/'
            }
        }
    }
}