Debian Package Tutorial (dpkg/.deb)

Introduction

Debian Package tool dpkg is used on Debian, Ubuntu, Kali, Linux Mint, and other Debian based Linux distributions. This tutorial covers the basics of creating custom .deb packages and managing them with dpkg and apt. We will cover the process of creating your own deb file to distribute your package easily. It is aimed at people who are interested in learning the basics of creating and managing packages in Debian based distributions. Read more about The .deb file format

A .deb file is a Debian package, but really it is just a standard Unix archive (.ar) file. The dpkg tool is the Debian package manager and apt is a higher level tool for managing packages which uses dpkg under the hood.

List installed packages

List packages with dpkg or apt:

dpkg -l       # List installed packages
dpkg -s mypkg # Get status of specific package

apt list --installed # List installed packages
apt list # List *all* packages in available repos

Create a package

You can make and distribute your own .deb package very easily. To start fresh, create a new directory named after your package. For example, mypkg. This directory will store the package metadata and the package contents. Inside the project directory, there needs to be one special directory (DEBIAN) with one special file inside it (control).

Read more about Debian control file fields.

# Minimum required structure for a package
mypkg-1.0.0/     # Directory
└── DEBIAN/      # Directory
    └── control  # File

A more practical example with a post-installation script:

mypkg/             # Directory
├── DEBIAN/        # Directory
│   └── control    # Control file
│   └── postinst   # Post install script
├── etc/my.ini     # Optionally any other files that you need to include
└── opt/mylib/     # on the destination system during installation

This is a minimal example of the DEBIAN/control file:

Package: mypkg
Version: 1.0.0
Maintainer: Your Name <[email protected]>
Description: My test package, please ignore
Homepage: https://github.com/username/projectname
Architecture: all
Depends: git, python3 (>=3.5), openjdk-8-jre-headless|openjdk-8-jre|openjdk-8-jdk-headless|openjdk-8-jdk

The Depends line is optional, but frequently needed. The example above shows how to add multiple dependencies, how to specify a minimum version with python3, and how to add a dependency that is satisfied by one of many options. There are many versions of java listed and any one will satisfy the requirement. If none of them are installed, it will start from the first one in the list and try to install it. This way, it will work if the user has version 8 of the JDK or JRE in full or headless variant. If none of them are installed it will install the smallest version (the headless jre).

Build the package by running dpkg -b on the project directory like this:

# Build mypkg directory in to .deb package
dpkg -b ./mypkg ./mypkg_1.0.0-0_amd64.deb

# Naming format: <name>_<version>-<release>_<arch>.deb
# Version is the version number of the app being packaged
# Release number is the version number of the *packaging* itself.
# The release number might increment if the package maintainer
# updated the packaging, while the version number of the application
# being packaged did not change.

# Inspect information like size, version, dependencies
dpkg -I mypkg.deb
# Example output of `dpkg -i mypkg.deb`

new debian package, version 2.0.
size 666 bytes: control archive=301 bytes.
    238 bytes,     6 lines      control
Package: mypkg
Version: 1.0.0
Maintainer: Your Name <[email protected]>
Description: My test package, please ignore
Architecture: all
Depends: git, python3 (>= 3.5), openjdk-8-jre-headless|openjdk-8-jre|openjdk-8-jdk-headless|openjdk-8-jdk      

It's a special little package, but it's lonely without any files to install. Normally a package has some contents like a shared library, man pages, documentation, an executable program, or systemd service files.

The next thing we'll need to do is add files to the package. Some examples of things you might include are:

  • an executable or a shell script launcher in /usr/local/bin/
  • man pages in /usr/share/man
  • configuration files in /etc/
  • libraries in /usr/local/lib
  • header files in /usr/local/include

In this example, we'll add a shell launch script for a Java JAR file:

/usr/bin/mylauncher
#!/bin/bash
# Launch script to kick off Java JAR (/usr/bin/mylauncher)

java -jar /usr/share/java/myapp.jar "[email protected]"

Be sure to chmod +x the script and place it in the mypkg/usr/local/bin/ directory.

Configuration files

List configuration files in DEBIAN/conffiles This will allow configuration files to optionally remain when uninstalling (remove vs purge). It also prevents updates from overwriting configuration files.

Example DEBIAN/conffiles:

/etc/myapp.conf
/etc/some/other/conf.ini

Pre/post install scripts

Examples:

DEBIAN/preinst
DEBIAN/postinst

An example DEBIAN/postinst script:

#!/bin/bash
# This `DEBIAN/postinst` script is run post-installation
mkdir /dir/needed/for/package

Package interrelationships

There are some other variables you can specify in the control file:

  • Depends
  • Recommends
  • Suggests
  • Breaks
  • Conflicts
  • Provides
  • Replaces
  • Enhances

These can be useful to warn people if your package conflicts with another package that is already installed. You can also replace or enhance existing packages. If other packages would make your package work better, you can recommend and suggest other packages when the user installs your package.

Read more about package interrelationship fields.

Print package information

You can use dpkg and apt-cache to get some information about packages.

# Print details about a package file (size, version, dependencies)
dpkg -I mypkg.deb

# Print status (is it installed?)
dpkg -s <package_name>

# Show package info (even uninstalled ones from repos)
apt-cache show <package_name>

Print package contents

If you want to review the contents of a .deb package before installing it, you can print the contents with the -c flag.

dpkg -c mypkg-1.0.0-0_amd64.deb

Extract package contents

If you want to extract the contents of a .deb file, use the -X flag for verbose extraction, or -x for quiet extraction.

dpkg -X mypkg-1.0.0-0_amd64.deb /where/to/exctact/

Install a package

Usually, two options are available for installing .deb packages. One is dpkg and the other is apt which is built on top of dpkg.

If you don't have the dependencies installed you will have to install them yourself if you use dpkg -i. Alternatively, you can use apt. I recommend using apt because it still uses dpkg under the hood, but it handles dependencies and is more user-friendly.

# Install package along with any dependencies it needs
sudo apt install ./mypkg.deb

# Install package, ignore and warn about unmet dependencies
sudo dpkg -i mypkg.deb

# If you need to install dependencies that were not
# installed because you used `dpkg -i` instead of `apt install`
sudo apt --fix-broken install

# Get status of package
dpkg -s mypkg  

Searching for packages in apt repositories

You can use apt-cache to search for packages in your apt repositories. These will need to be installed with apt install though not dpkg.

Search like this:

apt-cache search alien

Uninstall a package

You can uninstall a package using remove but it will leave the configuration files. To also remove the configuration files, use purge.

dpkg --remove package_name # Leaves config files
dpkg --purge package_name  # Removes config files too

# Or with apt
apt remove package_name
apt purge package_name

Listing files that belong to a package

This can be useful when trying to figure out what the executable file names are in /usr/bin or when trying to find local documentation.

# List all files that are included in the `ruby` package
dpkg -L ruby
dpkg -L ruby2.5-doc

Find which package owns a file

If you have a file on your system and you want to see if it belongs to a package, you can use dpkg -S <filepath> to see which package owns it.

You can also use apt-file search <filename> to see which packages in the repositories contain a file with that name.

For example "What package created this /etc/qwerty.conf file?" or "Which package owns this executable?", or "Which packages do I need to install to get gl.h?" can be answered with:

# Figure out which package owns a specific file
dpkg -S /etc/qwerty.conf
dpkg -S /usr/bin/python3

# Search apt repositories for packages that contain file
# Find any package that includes a `gl.h`
apt-file search "gl.h"

Security notes

Only Use trusted packages and repositories only. You install packages with root privileges and you will be giving full reign on your machine with a package. Do not run any package you are not 100% confident it is from a trusted source.

GPG signing is a good way to ensure integrity and authenticity, that is, it has not been modified and the package came from the expected author.

You can learn more about how to sign files with GPG in my GPG Basics Tutorial. GPG is a great cryptography tool to be familiar with and worth taking the time to learn it. You can also use it to encrypt emails so only the intended recipient can read it, encrypting archives or PDFs, verifying signatures from others, and and many other practical uses.

Convert a .deb to .rpm and other formats

If you need a RedHat .rpm file to install in CentOS, RedHat, or Fedora, you can use the alien tool to convert packages. http://joeyh.name/code/alien/

sudo apt install alien

alien --help

alien --to-rpm my_pkg.deb

Some other options are:

-d, --to-deb   Generate a Debian deb package (default).
-r, --to-rpm   Generate a Red Hat rpm package.
    --to-slp   Generate a Stampede slp package.
-l, --to-lsb   Generate a LSB package.
-t, --to-tgz   Generate a Slackware tgz package.

Debhelper tool

I do not have much experience with this tool but it is worth a mention. The debhelper tool provides some utility and code generation features. Here is how you can install it and explore more.

sudo apt install debhelper
man dh

# See what tools are available by entering
dh_<tab><tab> # Get the autocomplete options

# Generate a new Debian package template
sudo apt install dh-make
# From inside a directory w/ name like: mypkg-1.0.0
dh_make --createorig

Conclusion

You should now feel comfortable working with and creating your own Debian packages, how to get information about a package, how to find which package a file belongs to, and other common tasks.