How to create a Debian .deb package

By David Mytton,
CEO & Founder of Server Density.

Published on the 5th February, 2010.

A few weeks ago we announced that the agent for our server monitoring application, Server Density, was available as a Debian or Red Hat package, with associated repositories. Over my next few posts I will be outlining how we created our Linux-based packages and repositories, and what our steps are going to be to improve these processes in the future.

Structure of a Debian package

Debian packages must adhere to a strict directory structure. This includes a so-called control file and other scripts that look after what happens during installation of the package. Here’s a sample of our directory structure:

The control file, DEBIAN/control

The control file is the core of the Debian package; it contains all relevant metadata. Things such as package name, version, supported architectures, and dependancies are all included in this file. Here is what our current control file looks like:

Package: sd-agent
Version: 1.4.2
Architecture: all
Essential: no
Section: web
Priority: optional
Depends: python (>=2.3)
Maintainer: Ryan Duffield
Installed-Size: 96
Description: The Server Density monitoring agent.

The conffiles, DEBIAN/conffiles

Configuration files, or “conffiles”, are files that are included within a Debian package that may be changed by a user. When uninstalling the package, a user or system administrator dealing with the package may not want his or her configuration files removed. Running sudo apt-get remove sd-agent will remove all installed package files except for those listed in the DEBIAN/conffiles file. Here is what ours looks like:

/etc/sd-agent/config.cfg
/etc/init.d/sd-agent

If a user truly wants to remove everything including the configuration files, this can be done by using the purge command instead of remove: sudo apt-get purge sd-agent.

The md5sums file (DEBIAN/md5sums)

This file is a list of MD5 checksums for all files contained within the package that will actually be extracted to the system. This can be most easily generated using a combination of commands:

$ find . -type f ! -regex '.*.hg.*' ! -regex '.*?debian-binary.*' ! -regex '.*?DEBIAN.*' -printf '%P ' | xargs md5sum > DEBIAN/md5sums

The postinst and prerm scripts, DEBIAN/postinst and DEBIAN/prerm

Many packages need to perform actions before or after specific events during the package installation or uninstallation process. Debian packages accommodate for this via scripts. For instance, after installation, our agent package installs its init script automatically; it also needs to byte-compile our Python libraries. Below is the script that is run after installation, postinst:

#!/bin/sh
python -m compileall /usr/bin/sd-agent/
update-rc.d -f sd-agent defaults

Similarly, the agent removes those byte-compiled Python libraries and init script from system startup after uninstallation. This is handled by prerm:

#!/bin/sh
if [ "$1" = "remove" ]; then
rm /usr/bin/sd-agent/*.pyc
update-rc.d -f sd-agent remove
fi

The rest of it

The remainder of the directory structure must resemble the resultant structure after installation of the package. For example, because the agent is installed to /usr/bin/sd-agent, there is a usr/bin/sd-agent directory within our package root.

Creating the package

When all of the above is in place, creating the actual Debian package, or .deb file, is easy:

$ dpkg -b pkg-debian/ sd-agent_1.4.2_i386.deb
$ dpkg-deb: building package sd-agent' insd-agent_1.4.2_i386.deb'.

Mistakes made along the way

This was our first attempt at creating a Debian package, so, naturally, some mistakes were made along the way!

Our initial control file was wrong; specifically, our Installed-Size value was calculated incorrectly. I had originally read that this value was supposed to be expressed in bytes. However, after releasing our first package, I noticed that apt-get displayed a message notifying me that the agent would take up over 100 MB of disk space. This was obviously incorrect. This field’s value needs to be expressed in kilobytes, as outlined here.

Another mistake made was accidentally including Mercurial’s various files (.hg folder, .hgignore, etc.) in the first package version. This was kindly pointed out by one of our customers, and promptly fixed. If one wants to see a list of files currently “owned” by a given package, one can do so by using dpkg with the -L switch. For instance, to see the files that the Server Density agent is responsible for, one can run:

dpkg -L sd-agent

Other Linux packages

As mentioned, we also created a Red Hat package for the agent, and Debian and Red Hat repositories. My next article will outline how we created the Red Hat RPM for the agent.

Free eBook: The 9 Ingredients of Scale

From two students with pocket money, to 20 engineers and 80,000 servers on the books, our eBook is a detailed account of how we scaled a world-class DevOps team from the ground up. Download our definitive guide to scaling DevOps and how to get started on your journey.

Help us speak your language. What is your primary tech stack?

What infrastructure do you currently work with?

  • If you’re creating debs and RPMs from Python packages it’s worth checking out FPM: https://github.com/jordansissel/fpm/wiki

  • ikt

    thank you =)

  • Xavier Ashe

    I wanted to add to the list of thank yous. This is the most straightforward guide to setting up a .deb package. I did read somewhere else that any file in /etc is treated like a user-editable configuration file. So you don’t have to add anything to conffiles that is in /etc. Also, conffiles is an optional file.

Articles you care about. Delivered.

Help us speak your language. What is your primary tech stack?

Maybe another time