Create Ubuntu DEB Package from source code (.tar.gz, .tgz)

Create Ubuntu DEB Package

If you have ever compiled software from a .tar.gz or .tgz source tarball on Ubuntu, you already know the pain that follows. You run ./configure, make, and make install, the software works fine, and then one day you need to remove it. There is no clean uninstall path, no version tracking, and APT has no idea the software even exists on your system. That is the core problem this Linux server tutorial solves.

Creating an Ubuntu DEB package from source code gives you a structured, reversible, and APT-managed installation. You can install it, upgrade it, share it with teammates, or remove it completely without leaving orphaned files scattered across your filesystem.

In this guide, you will learn two practical methods to configure an Ubuntu DEB package from a source tarball: a quick approach using checkinstall for local use, and a full approach using dpkg-buildpackage for distribution-quality packaging. Both methods are tested on Ubuntu 20.04, 22.04, and 24.04 LTS.

By the end, you will have a working .deb file built from a real upstream source tarball, validated, installed, and cleanly removable through Ubuntu’s native package management system. This is the workflow senior sysadmins use, and it is not as complicated as the Debian documentation makes it look.

Table of Contents

What Is an Ubuntu DEB Package and Why Build One?

A .deb file is the native binary package format used by Debian and Ubuntu. Internally, it is a Unix archive containing two tar sub-archives: one holding control metadata and one holding the actual program files. These archives can be compressed using gzip, bzip2, lzma, or xz.

When you install a .deb file with dpkg or APT, the package manager registers every file it places on your system. That registration is what gives you clean removal, version tracking, and dependency resolution.

The Problem with make install

Running make install directly from source drops files into /usr/local/bin, /usr/local/lib, and other directories with no record of what was placed where.

You cannot upgrade cleanly. You cannot remove cleanly. And if two packages install conflicting files, you have no tooling to detect or resolve that conflict. This is why packaging matters, even for software you only use internally.

checkinstall vs. dpkg-buildpackage

Both tools produce a .deb file, but they serve different purposes. Here is a direct comparison:

Feature checkinstall dpkg-buildpackage
Setup complexity Low Medium to High
Output quality Basic .deb Policy-compliant .deb
Best for Local personal use Distribution, PPAs, CI/CD
Lintian-clean output No Yes, with tuning
Build time Fast Slightly longer

Use checkinstall when you want a quick Ubuntu DEB package setup on a single machine. Use dpkg-buildpackage when you need a package that meets Debian policy standards for sharing or publishing.

Prerequisites

Before you begin this Linux server tutorial, confirm the following:

System requirements:

  • Ubuntu 20.04 LTS, 22.04 LTS, or 24.04 LTS (desktop or server)
  • A non-root user account with sudo privileges
  • Active internet connection to download packages and source tarballs
  • At least 500 MB of free disk space in your build directory

Knowledge requirements:

  • Comfort with running commands in a Linux terminal
  • Basic understanding of tar extraction and file navigation
  • Familiarity with a terminal text editor such as nano or vim

Tools you will install in Step 1:

  • build-essential (gcc, g++, make)
  • checkinstall
  • devscripts, dh-make, dpkg-dev
  • lintian

If you are building packages you intend to distribute or upload to a Launchpad PPA, consider running all of this inside a clean VM or Docker container to avoid polluting your host system’s build environment.

Step 1: Update Your System and Install Build Dependencies

Every good Ubuntu DEB package setup starts with a fully updated system. Running builds on a partially updated system is one of the most common sources of subtle dependency errors that are hard to debug.

Update your package index and upgrade installed packages

sudo apt update && sudo apt upgrade -y

This command refreshes your local package list from Ubuntu’s repositories and upgrades any outdated packages. Always do this before installing new development tools.

Install all required build tools in one command

sudo apt install build-essential automake autoconf libtool \
  pkg-config checkinstall devscripts dh-make dpkg-dev lintian -y

Here is what each tool does:

  • build-essential: Installs gcc, g++, make, and standard C library headers — the minimum toolchain for compiling C/C++ source code
  • checkinstall: Intercepts make install and generates a .deb file instead of writing files directly to the filesystem
  • devscripts: Provides helper scripts like dch (changelog editor) and debuild (high-level build wrapper)
  • dh-make: Generates a debian/ directory skeleton inside your source tree
  • dpkg-dev: Provides dpkg-buildpackage and other core packaging utilities
  • lintian: Static analysis tool that checks your package against official Debian policy rules

Verify the key tools installed correctly

dpkg-buildpackage --version
lintian --version
checkinstall --version

You should see version strings for each tool. If any command returns “not found,” re-run the install command above.

Step 2: Download and Prepare Your Source Tarball

For this tutorial, you will use Dante, a free SOCKS server and client, as the example package. Dante is a real-world C project with a standard GNU build system, making it an ideal example.

Download the upstream source tarball

mkdir -p ~/build && cd ~/build
wget http://www.inet.no/dante/files/dante-1.3.2.tar.gz

wget downloads the tarball into your ~/build directory. The -p flag in mkdir ensures no error if the directory already exists.

Extract the tarball

tar zxvf dante-1.3.2.tar.gz
  • z: decompress using gzip
  • x: extract the archive
  • v: verbose output (shows each file being extracted)
  • f: specifies the filename

This creates a directory named dante-1.3.2/.

Verify the directory name format

The directory name must follow the name-version format in lowercase. Debian packaging tools parse this directory name to determine the package name and version automatically.

ls ~/build/

Expected output:

dante-1.3.2  dante-1.3.2.tar.gz

Create the orig tarball for dpkg-buildpackage (Method 2 only)

cp dante-1.3.2.tar.gz dante_1.3.2.orig.tar.gz

Note the underscore between name and version in the copy. This naming convention (name_version.orig.tar.gz) is required by dpkg-buildpackage. The hyphen format is for the directory; the underscore format is for the orig tarball.

Navigate into the source directory

cd dante-1.3.2

All subsequent commands run from inside this directory.

Step 3: Configure and Build the Source Code

This step is identical for both Method 1 (checkinstall) and Method 2 (dpkg-buildpackage). You are compiling the software before packaging it.

Run the configure script

./configure

The ./configure script checks your system for required libraries and compiler features, then generates a Makefile tailored to your environment. If it fails, it will tell you exactly which library or header is missing. Install that dependency with apt and run ./configure again.

Compile the source code

make

make reads the generated Makefile and compiles the source files into binary executables. On a modern multi-core machine, speed up this step with:

make -j$(nproc)

$(nproc) outputs the number of available CPU cores, allowing make to parallelize the compilation. A successful build ends without any Error messages in the output.

Step 4: Method 1 — Quick DEB Packaging with checkinstall

This is the fastest way to create a functional Ubuntu DEB package from source. It requires no manual metadata configuration and works well for local deployments and internal servers.

Run checkinstall instead of make install

sudo checkinstall

Instead of writing files directly to your system like make install would, checkinstall monitors the installation and wraps all placed files into a .deb archive.

Respond to the interactive prompts

checkinstall will ask you several questions. Here are the recommended responses:

  • Package name: dante (lowercase, no spaces)
  • Version: 1.3.2
  • Maintainer: Your name and email
  • Summary: A short one-line description

After you confirm, checkinstall generates a file like dante_1.3.2-1_amd64.deb in your current directory.

Install and verify the generated package

sudo dpkg -i dante_1.3.2-1_amd64.deb
dpkg -s dante

dpkg -s prints the package status, version, architecture, and description — confirming that APT now tracks this installation.

Remove the package cleanly

sudo apt remove dante

Using apt remove instead of dpkg -r is preferred because APT handles any dependency cleanup automatically.

Step 5: Method 2 — Full DEB Packaging with dpkg-buildpackage

This method produces a policy-compliant .deb package suitable for Launchpad PPAs, Debian repositories, or sharing across teams. It takes more setup but gives you a properly structured package that passes lintian checks.

Generate the debian/ directory skeleton

From inside ~/build/dante-1.3.2/, run:

dh_make -s --createorig -e [email protected]
  • -s: creates a single binary package
  • --createorig: generates the .orig.tar.gz file automatically
  • -e: sets your email address in the package metadata

This creates a debian/ directory with the following structure:

debian/
├── changelog
├── compat
├── control
├── copyright
├── rules
└── source/
    └── format

Configure debian/control — the package metadata file

Open the control file:

nano debian/control

Fill in or edit these key fields:

Source: dante
Section: net
Priority: optional
Maintainer: Your Name <[email protected]>
Build-Depends: debhelper-compat (= 13)
Standards-Version: 4.6.0

Package: dante
Architecture: any
Depends: ${shlibs:Depends}, ${misc:Depends}
Description: Free SOCKS server implementation
 Dante is a free implementation of the SOCKS proxy protocol,
 version 4 and version 5. It can be used as a firewall bypass tool.

Key field explanations:

  • Architecture: any means the package compiles to native code and must be built per-architecture. Use all for scripts or architecture-independent data
  • Depends: ${shlibs:Depends} is a variable that dpkg-buildpackage resolves automatically by scanning the compiled binaries for shared library links
  • The long Description must be indented with one space per line

Write debian/rules — the build instructions

Open the rules file:

nano debian/rules

A minimal modern rules file using the dh helper looks like this:

#!/usr/bin/make -f
%:
	dh $@

Make it executable:

chmod +x debian/rules

The dh command is the debhelper sequencer. It automatically runs the correct build, install, and packaging steps in the right order based on the build system it detects.

Update the changelog

Use dch to create a properly formatted changelog entry:

dch -i "Initial packaging of dante from upstream source"

Set the distribution to your Ubuntu release:

dch -r ""

The changelog format is strict. dch handles the formatting automatically so you do not introduce syntax errors.

Set the debhelper compat level

echo "13" > debian/compat

Debhelper compatibility level 13 is the current recommended level for Ubuntu 20.04 and later.

Build the package

cd ~/build
dpkg-buildpackage -us -uc
  • -us: do not sign the source package (for local builds)
  • -uc: do not sign the .changes file (for local builds)

A successful build produces these files in ~/build/:

  • dante_1.3.2-1_amd64.deb — the installable binary package
  • dante_1.3.2-1.dsc — the source package description
  • dante_1.3.2-1.debian.tar.xz — the debian/ directory as an archive
  • dante_1.3.2-1_amd64.changes — the changes file used for repository uploads

Step 6: Validate Your Package with Lintian

Before you install, share, or publish your Ubuntu DEB package, run it through lintian. This tool checks your package against the official Debian Policy Manual and reports errors and warnings.

lintian ~/build/dante_1.3.2-1_amd64.deb

For more detailed output with tag explanations:

lintian -v --explain-tags ~/build/dante_1.3.2-1_amd64.deb

Errors (E:) must be fixed before distribution. Warnings (W:) are context-dependent but should be reviewed.

Common lintian tags and what they mean:

  • W: no-copyright-file — your debian/copyright file is missing or empty. Add a valid license declaration
  • W: description-synopsis-is-duplicated — your short and long description are identical. Write a more detailed long description
  • E: bad-distribution-in-changes-file — the distribution field in debian/changelog does not match a valid Ubuntu release name

Step 7: Install, Test, and Remove the Package

With your validated .deb file ready, install it using dpkg:

sudo dpkg -i ~/build/dante_1.3.2-1_amd64.deb

Verify the installation registered correctly with APT:

dpkg -s dante

List every file the package installed on your system:

dpkg -L dante

Test that the binary actually runs:

sockd --version

When you are ready to remove it:

sudo apt remove dante

APT tracks this package just like any other software installed from Ubuntu’s repositories. Clean removal is guaranteed.

Troubleshooting Common Errors

Problem 1: dpkg-buildpackage fails with missing build dependencies

Error message: dpkg-checkbuilddeps: error: Unmet build dependencies

Solution: Add the missing package to Build-Depends in debian/control, then run:

sudo apt-get build-dep .

This command installs all packages listed in Build-Depends automatically.

Problem 2: dh_make fails with a directory naming error

Error message: Could not find a valid package name and version in the directory name

Solution: Your source directory must follow the exact name-version pattern in lowercase:

mv Dante-1.3.2 dante-1.3.2

Rename the directory, then re-run dh_make.

Problem 3: checkinstall fails after make succeeds

Solution: Make sure you ran ./configure and make without errors before running checkinstall. Never skip the make step and jump straight to checkinstall.

Problem 4: lintian reports W: no-copyright-file

Solution: Edit debian/copyright and add a valid license block. For a minimal fix:

Format: https://www.debian.org/doc/packaging-manuals/copyright-format/1.0/
Upstream-Name: dante
License: BSD-4-clause

Problem 5: debian/rules not executable

Error message: make: debian/rules: Permission denied

Solution: Run:

chmod +x debian/rules

This makes the rules file executable so dpkg-buildpackage can call it directly as a Makefile.

VPS Manage Service Offer
If you don’t have time to do all of this stuff, or if this is not your area of expertise, we offer a service to do “VPS Manage Service Offer”, starting from $10 (Paypal payment). Please contact us to get the best deal!

Save

Tech enthusiast with expertise in cloud systems, Linux Sysadmin servers, virtualization, Containerization, and automation among others

Related Posts