Debian Packaging📦
Debian packaging refers to the process of building and distributing software packages in the .deb
format, which Debian uses and its derivatives like Ubuntu. A Debian package contains all the files, metadata, and instructions necessary to install software on a system using the APT (Advanced Package Tool) or similar package managers.
Creating a Python File and Making it Executable 🐍
sudo apt update
vi greet-koushal.py
print("Hi This is koushal,Let's crack it up!")
sudo apt-get -y install python3-pip
sudo pip3 install pyinstaller --break-system-packages
pyinstaller --onefile greet-koushal.py
Packaging it as a Debian Package 📦
Before we can start packaging, we need a directory structure that follows Debian's packaging conventions. This naming format helps track software versions and architecture, and it looks like this:
<package-name>_<version>-<release-number>_<architecture>
Where:
package-name: The name of your package, which is
hello-world
in our case.version: The version of the software. We’ll use
0.0.1
here.release-number: Tracks different releases of the same version. Typically, this starts at
1
.architecture: The target architecture, such as
amd64
. If the package is platform-independent (like Python scripts), you can useall
.
Let’s create the directory now:
mkdir -p ~/example/hello-world_0.0.1-1_amd64
This directory will be our package's root. Since we want our "hello-world" program installed system-wide, we’ll place the binary in the appropriate location (/usr/bin/hello-world
).
2. Adding the Binary to the Package
Now, we’ll create the directories for the binary and copy our "hello-world" program:
cd ~/example/greet-koushal_0.0.1-1_amd64
mkdir -p usr/bin
cp /home/ubuntu/dist/greet-koushal usr/bin/.
This places our executable in usr/bin
, where it will be accessible system-wide after installation.
3. Creating the Control File
Every Debian package needs a control file that contains metadata about the package, such as its name, version, maintainer, and dependencies. This file will go into a special DEBIAN
folder.
Let’s create the control file:
mkdir -p ~/example/greet-koushal_0.0.1-1_amd64/DEBIAN
Now, we’ll add the following information to the control file:
echo "Package: greet-koushal
Version: 0.0.1
Maintainer: example <example@example.com>
Depends: python3.12
Architecture: amd64
Homepage: http://example.com
Description: Greetings from koushal" \
> ~/example/greet-koushal_0.0.1-1_amd64/DEBIAN/control
Package: The name of the package (
hello-world
).Version: The version of the software (
0.0.1
).Maintainer: The person responsible for the package.
Depends: Any dependencies needed for the program to run (e.g.,
libc6
).Architecture: The platform architecture (
amd64
in this case).Homepage: The official site for the program.
Description: A brief description of the software.
4. Building the .deb
Package
With the directory structure and control file in place, it’s time to build the .deb
package! 🎉
dpkg --build ~/example/greet-koushal_0.0.1-1_amd64
This command will generate the .deb
package under the ~/example/
directory. You should now have greet-koushal_0.0.1.deb
ready to distribute
Creating an APT Repository 🗂️
Let’s kick things off by creating a directory structure to hold our .deb
packages. We'll be following the standard APT repository format, which organizes packages into a pool directory.
mkdir -p ~/example/apt-repo/pool/main/
Next, we’ll copy our .deb
package (in this case, hello-world
) into the directory we just created:
cp ~/example/greet-koushal_0.0.1-1_amd64.deb ~/example/apt-repo/pool/main/.
This pool will store all the .deb
files that will be available in your repository. Larger repositories, like the official Ubuntu ones, further organize packages into sub-directories. For instance, Vim-related packages can be found under /ubuntu/pool/main/v/vim/
.
2. Generating Package Metadata
APT repositories require a list of available packages and metadata about each package. This is done by creating a Packages
file.
Let’s first create a directory for this metadata:
mkdir -p ~/example/apt-repo/dists/stable/main/binary-amd64
If you want to support multiple architectures (like i386
, arm64
, etc.), create a similar directory for each.
Now, we’ll generate a Packages
file using the dpkg-scanpackages
command:
cd ~/example/apt-repo
dpkg-scanpackages --arch amd64 pool/ > dists/stable/main/binary-amd64/Packages
This Packages
file contains a list of all the .deb
files in your repository, along with metadata about each.
3. Compressing the Packages File
To make things more efficient, APT prefers downloading compressed metadata. So let’s compress the Packages
file:
cat dists/stable/main/binary-amd64/Packages | gzip -9 > dists/stable/main/binary-amd64/Packages.gz
By compressing it, you’re ensuring that your repository will work faster, and this is also often a required step. You can even use other compression types like bz2
or lzma
depending on your needs. But for simplicity, we’ll stick with gzip
.
4. Creating the Release File
Now, we need a Release
file, which provides additional metadata about the repository itself, like its origin, architectures, and a list of hash sums for each Packages
file.
Let’s look at a sample Release
file format:
makefileCopy codeOrigin: Example Repository
Label: Example
Suite: stable
Codename: stable
Version: 1.0
Architectures: amd64 arm64 arm7
Components: main
Description: An example software repository
It also includes checksums (MD5, SHA1, SHA256) to validate the integrity of the repository’s Packages
files. Rather than manually crafting this file, we’ll automate its creation with a bash script!
5. Automating the Release File Creation
Here’s a quick bash script to generate the Release
file automatically:
echo '#!/bin/sh
set -e
do_hash() {
HASH_NAME=$1
HASH_CMD=$2
echo "${HASH_NAME}:"
for f in $(find -type f); do
f=$(echo $f | cut -c3-) # remove ./ prefix
if [ "$f" = "Release" ]; then
continue
fi
echo " $(${HASH_CMD} ${f} | cut -d" " -f1) $(wc -c $f)"
done
}
cat << EOF
Origin: Example Repository
Label: Example
Suite: stable
Codename: stable
Version: 1.0
Architectures: amd64 arm64 arm7
Components: main
Description: An example software repository
Date: $(date -Ru)
EOF
do_hash "MD5Sum" "md5sum"
do_hash "SHA1" "sha1sum"
do_hash "SHA256" "sha256sum"
' > ~/example/generate-release.sh && chmod +x ~/example/generate-release.sh
This script will automatically generate a Release
file with all the required hashes for your APT repository.
To run the script and create the Release
file, use this command:
cd ~/example/apt-repo/dists/stable
~/example/generate-release.sh > Release
Signing your apt
Repository With GPG🗝️
GPG keys are essential in APT repositories for ensuring security, authenticity, and integrity of packages. Here's why:
Package Authenticity: GPG signatures verify that the package is from a trusted source, ensuring it hasn't been tampered with.
Data Integrity: Signatures prevent malicious alterations by detecting any changes in the package since it was signed.
Trust System: Users trust GPG-signed packages, creating a chain of trust between the repository and users.
Preventing Malware: GPG keys protect against installing untrusted or harmful software.
Maintaining Credibility: Signed packages reassure users of the repository's legitimacy and security.
echo "%echo Generating an example PGP key
Key-Type: RSA
Key-Length: 4096
Name-Real: koushal
Name-Email: koushalakash3@gmaail.com
Expire-Date: 0
%no-ask-passphrase
%no-protection
%commit" > /tmp/example-pgp-key.batch
export GNUPGHOME="$(mktemp -d ~/example/pgpkeys-XXXXXX)"
gpg --no-tty --batch --gen-key /tmp/example-pgp-key.batch
gpg --armor --export koushal > ~/example/pgp-key.public
gpg --armor --export-secret-keys koushal > ~/example/pgp-key.private
cat ~/example/pgp-key.private | gpg --import
cat ~/example/koushal-apt-repo/dists/stable/Release | gpg --default-key example -abs > ~/example/koushal-apt-repo/dists/stable/Release.gpg
cat ~/example/koushal-apt-repo/dists/stable/Release | gpg --default-key koushal -abs --clearsign > ~/example/koushal-apt-repo/dists/stable/InRelease
Hosting the APT Repository 🌐
you can host your Repository in Git hub for free or in some other way like Apache or Nginix. You could refer my APT repository attached here
Workflow between the APT client and APT Repository👈👉
APT Client sends a request (
apt update
) for updated metadata.Repository sends the
Release
file andRelease.gpg
to verify the repository’s authenticity.APT verifies the GPG signature of the
Release
file.APT downloads the
Packages
file (orPackages.gz
), containing package metadata.APT verifies the hash of the
Packages
file against theRelease
file.User requests a package (
apt install <package-name>
).Repository sends the
.deb
package file.APT verifies the hash of the
.deb
package using the hash from thePackages
file.APT installs the package and resolves any dependencies.
This process ensures both the authenticity (via GPG signatures) and integrity (via hashes) of the packages downloaded and installed on your system.
Subscribe to my newsletter
Read articles from Koushal Akash RM directly inside your inbox. Subscribe to the newsletter, and don't miss out.
Written by