Authors Top

If you have a few years of experience in the Linux ecosystem, and you’re interested in sharing that experience with the community, have a look at our Contribution Guidelines.

1. Overview

A Debian package is the simplest and most efficient way of distributing software in Debian-based distributions. It takes care of managing dependencies and provides a good interface for install/upgrade/uninstall operations.

The official way of creating a package involves a lot of steps and processes. In this tutorial, we’ll look at a simpler way of creating these packages. However, the official way of package creation is ideal and recommended for production purposes.

2. Preparing the Files

2.1. Structure of .deb Package

In Debian-based distributions, one of the ways we install applications is by downloading the .deb package file and using dpkg command to install it. This “deb package” is an archive of binaries and configuration files associated with a software application. All the files inside the archive are kept in a specific folder structure.

During installation, in the target machine, the binaries and configuration files go into a similar folder structure from the root folder.

Let’s look at an example to understand more clearly. First, we create a working folder for the build:

[email protected]:~/Documents/deb/build$ mkdir test

Please note the path – we’ll be changing the folder as and when we progress through this exercise.

Then, we prepare files for our application. To keep things simple, let’s have two files:

  • test.sh executable
  • test.conf configuration file

For these files, we’ll keep the contents as below for this exercise:

[email protected]:~/Documents/deb/build/test$ cat test.conf 
NAME=Test
[email protected]:~/Documents/deb/build/test$ cat test.sh
#!/bin/bash
. test.conf
echo "Hi $NAME"

We know that the executable files in Debian are kept in the /bin folder and the configuration files in the /etc folder. Following the convention, we’ll keep the test.sh file in the /bin folder and test.conf in the /etc folder.

Hence, we create two folders, bin and etc, in our current directory:

[email protected]:~/Documents/deb/build/test$ mkdir {bin,etc}
[email protected]:~/Documents/deb/build/test$ ls
bin  etc  test.conf  test.sh

Now, let’s move the executable and configuration files to their respective folders:

[email protected]:~/Documents/deb/build/test$ mv test.conf etc/
[email protected]:~/Documents/deb/build/test$ mv test.sh bin/
[email protected]:~/Documents/deb/build/test$ ls
bin  etc

With this, we’ve placed our files in a folder structure that would be the same once it’s installed in the target machine.

2.3. The control File

Finally, we need a control file that contains the metadata for the package. This is a text file with fields and descriptions. The supported fields are:

  • Package (Required): Name of package
  • Version (Required): Version of the package
  • Maintainer (Required): Name and email of maintainer
  • Architecture (Required): Supported target machine architecture
  • Description (Required): Short description of the package
  • Section: Package classification like admin, database, kernel, utils
  • Priority: Whether the package is optional or required
  • Essential: Whether the package is always required
  • Depends: List other dependent packages like libc6 (>= 2.2.4-4)
  • Homepage: URL of the website associated with the package
  • Package-Type: Indicate the types, like deb or udeb, for example

As mentioned above, some fields are required and others are optional.

Using this information, let’s create a control file with the required fields and some of the recommended fields. This file goes under a folder named DEBIAN:

[email protected]:~/Documents/deb/build/test$ ls
bin  DEBIAN  etc
[email protected]:~/Documents/deb/build/test$ cat DEBIAN/control 
Package: test
Version: 1.0-1
Section: utils
Priority: optional
Architecture: all
Maintainer: Baeldung <[email protected]>
Description: This is a test application
 for packaging

3. Building the Package

With that, we’re ready to build our package. And for that, we can use the dpkg-deb command:

[email protected]:~/Documents/deb/build$ dpkg-deb --root-owner-group --build test
dpkg-deb: building package 'test' in 'test.deb'.
[email protected]:~/Documents/deb/build$ ls
test  test.deb

As we can see, a test.deb file is created successfully. With that, we are almost ready with our package.

4. Verify the Package

4.1. Check Contents

Once the package is created, we can verify if the files are present in it by running the dpkg command:

[email protected]:~/Documents/deb/build$ dpkg -c test.deb 
drwxr-xr-x thinkpalm/thinkpalm 0 2021-12-23 12:09 ./
drwxr-xr-x thinkpalm/thinkpalm 0 2021-12-23 11:30 ./bin/
-rwxr-xr-x thinkpalm/thinkpalm 40 2021-12-23 11:15 ./bin/test.sh
drwxr-xr-x thinkpalm/thinkpalm  0 2021-12-23 11:30 ./etc/
-rw-r--r-- thinkpalm/thinkpalm 10 2021-12-23 11:15 ./etc/test.conf

From the results, we see that it contains the files we have added in their expected paths.

4.2. Linting

In order to further comply with the Debian packaging conventions, we can lint the package. For this, we use the tool called lintian.

Let’s see how we can use this tool:

[email protected]:~/Documents/deb/build$ lintian test.deb 
E: test: debian-changelog-file-missing
E: test: file-in-etc-not-marked-as-conffile etc/test.conf
E: test: no-copyright-file
W: test: script-with-language-extension bin/test.sh
W: test: binary-without-manpage bin/test.sh

After running the command, we can see some errors marked as E and warnings marked as W.

Let’s check how we can fix these, one by one.

Changelog File Missing:

To fix this error, we can add a changelog file:

[email protected]:~/Documents/deb/build$ cat changelog.Debian 
test (1.0-2) stable; urgency=low

  [ Baeldung ]
  * Changes to installer 

 -- Baeldung <[email protected]>  Thu,  23 Dec 2021 11:30:00 +0100 

test (1.0-1) stable; urgency=low

  [ Baeldung ]
  * Wonderful program to print the name ;)

 -- Baeldung <[email protected]>  Thu,  23 Dec 2021 11:00:00 +0100 
[email protected]:~/Documents/deb/build$ gzip --best -n changelog.Debian 
[email protected]:~/Documents/deb/build$ mkdir -p test/usr/share/doc/test
[email protected]:~/Documents/deb/build$ cp changelog.Debian.gz test/usr/share/doc/test/

Marking File as Conf File:

In order to fix this error, we can add a conffile in the DEBIAN folder:

[email protected]:~/Documents/deb/build$ cat test/DEBIAN/conffiles 
/etc/test.conf

Adding Copyright File:

To fix this one, we can add a copyright file:

[email protected]:~/Documents/deb/build$ cat test/usr/share/doc/test/copyright 
test

Copyright: 2020 Baeldung <[email protected]>

2020-12-23

The entire code base may be distributed under the terms of the GNU General
Public License (GPL), which appears immediately below.  Alternatively, all
of the source code as any code derived from that code may instead be
distributed under the GNU Lesser General Public License (LGPL), at the
choice of the distributor. The complete text of the LGPL appears at the
bottom of this file.

See /usr/share/common-licenses/(GPL|LGPL)

Removing Extension for Binary File:

Let’s remove the extension for the script file to fix this error:

[email protected]:~/Documents/deb/build$ mv test/bin/test.sh test/bin/test 

Adding Man Entry for Binary:

Let’s add a man file to fix this error:

[email protected]:~/Documents/deb/build$ cat test.1
.\"                                      Hey, EMACS: -*- nroff -*-
.\" (C) Copyright 2020 Baeldung <[email protected]>
.\"
.TH TEST 1 
.SH NAME
test \- test application
.SH SYNOPSIS
.B test.sh 
.SH DESCRIPTION
The 
.B test 
prints the name.
.SH SEE ALSO
.BR echo (1).
.SH AUTHORS
The
.B test 
script was written by 
Baeldung <[email protected]>
.PP
This document was written by Baeldung <[email protected]> for Debian.

[email protected]:~/Documents/deb/build$ gzip --best -n test.1
[email protected]:~/Documents/deb/build$ ls
build.sh  changelog.Debian.gz  changelog.gz  test  test_1.0-1.deb  test.1.gz
[email protected]:~/Documents/deb/build$ mkdir -p test/usr/share/man/man1
[email protected]:~/Documents/deb/build$ cp test.1.gz test/usr/share/man/man1/

The final folder structure would be:

[email protected]:~/Documents/deb/build$ tree test
test
├── bin
│   └── test
├── DEBIAN
│   ├── conffiles
│   └── control
├── etc
│   └── test.conf
└── usr
    └── share
        ├── doc
        │   └── test
        │       ├── changelog.Debian.gz
        │       └── copyright
        └── man
            └── man1
                └── test.1.gz

9 directories, 7 files

Let’s build this again:

[email protected]:~/Documents/deb/build$ dpkg-deb --root-owner-group --build test
dpkg-deb: building package 'test' in 'test.deb'.
[email protected]:~/Documents/deb/build$ mv test.deb test_1.0-2.deb
[email protected]:~/Documents/deb/build$ lintian test_1.0-2.deb
[email protected]:~/Documents/deb/build$

Now, we can see all the errors and warnings are fixed.

5. Conclusion

In this tutorial, we went through the process of creating a deb package with minimum steps. We hope this will be a good starting point for learning to create Debian packages.

Authors Bottom

If you have a few years of experience in the Linux ecosystem, and you’re interested in sharing that experience with the community, have a look at our Contribution Guidelines.

Comments are closed on this article!