Packaging a Python App to Executable .deb Binary
I am sharing how I packaged my python application into an executable .deb package in this tutorial.
β Abhishek Kumar

You know that moment when you dive into a project, thinking, "This should be easy," and then hours later, you're buried under obscure errors, outdated forum posts, and conflicting advice?
Yeah, that was me while trying to package my Python app into a .deb
file.
It all started with my attempt to revive an old project, which some of our long-time readers might remember - Compress PDF.

Since Iβve been learning Python these days, I thought, why not customize the UI, tweak the logic, and give it a fresh start?
The python app was working great when running inside a virtual environment but I was more interested in shipping this app as a .deb binary, making installation as simple as dpkg -i app.deb
.
Every tutorial I read online, covered bits and pieces, but none walked me through the entire process. So here I am, documenting my experience while packaging my script into a .deb
file.
Choosing the right packaging tool
For turning a Python script into an executable, I am using PyInstaller. Initially, I tried using py2deb, a tool specifically meant for creating .deb
packages.
Bad idea. Turns out, py2deb
hasnβt been maintained in years and doesnβt support newer Python versions.
PyInstaller takes a Python script and bundles it along with its dependencies into a single standalone executable. This means users donβt need to install Python separately, it just works out of the box.
Step 1: Install PyInstaller
First, make sure you have PyInstaller installed. If not, install it using pip:
Check if it's installed correctly:
Step 2: Create the .deb package structure
To keep things clean and structured, .deb
packages follows a specific folder structure.
Letβs create it:

What each directory is for?
usr/bin/
: Stores the executable file.usr/share/applications/
: Contains the.desktop
file (so the app appears in the system menu).usr/share/icons/
: Stores the app icon.DEBIAN/
: Contains metadata like package info and dependencies.
Optional: Packaging dependencies
Before packaging the app, I wanted to ensure it loads assets and dependencies correctly whether it's run as a script or a standalone binary.
Initially, I ran into two major problems:
- The in-app logo wasnβt displaying properly because asset paths were incorrect when running as a packaged executable.
- Dependency errors occurred when running the app as an executable.
To keep everything self-contained and avoid conflicts with system packages, I created a virtual environment inside: pdf-compressor/usr/share/pdf-compressor
Then, I installed all the dependencies inside it:
This ensures that dependencies are bundled properly and wonβt interfere with system packages.
Now to ensure that the app correctly loads assets and dependencies, I modified the script as follows:
Whatβs happening here?
sys._MEIPASS
β When the app is packaged with PyInstaller, assets are extracted to a temporary folder. This ensures they are accessible.- Virtual environment path (
/usr/share/pdf-compressor/venv
) β If it exists, it is added tosys.path
, so installed dependencies can be found. - Assets paths β Dynamically assigned so they work in both script and standalone modes.
After making these changes, my issue was mostly resolved.
Step 3: Compiling python script into executable binary
Now comes the exciting part, turning the Python script into a standalone executable. Navigate to the root directory where the main Python script is located. Then run:
--onefile
: Packages everything into a single executable file--windowed
: Hides the terminal (useful for GUI apps)--name=compress-pdf
: Sets the output filename--add-data "assets:assets"
β Ensures images/icons are included.

After this, PyInstaller will create a dist/
, inside, you'll find compress-pdf
. This is the standalone app!
Try running it:
If everything works as expected, youβre ready to package it into a .deb
file.
Step 4: Move the executable to the correct location
Now, move the standalone executable into the bin directory:

Step 5: Add an application icon
I don't know about you but to me, an app without an icon or just generic gear icons feels incomplete. Icon gives the vibe to your app.
Letβs place the assets
directory which contains the icon and logo files inside the right directory:

Step 6: Create a desktop file
To make the app appear in the system menu, we need a .desktop
file. Open a new file:
Paste this content:
Exec
β Path to the executable.Icon
β App icon location.Terminal=false
β Ensures it runs as a GUI application.

Save and exit (CTRL+X
, then Y
, then Enter
).
Step 7: Create the control file
At the heart of every .deb
package is a metadata file called control
.
This file is what tells the Debian package manager (dpkg) what the package is, who maintains it, what dependencies it has, and a brief description of what it does.
Thatβs why defining them here ensures a smooth experience for users.
Inside the DEBIAN/
directory, create a control
file:
then I added the following content in it:

Step 8: Create the postinst script
The post-installation (postinst
) script as the name suggests is executed after the package is installed. It ensures all dependencies are correctly set up.
Add this content:
Whatβs happening here?
set -e
β Ensures the script stops on failure.- Creates a virtual environment β This allows dependencies to be installed in an isolated way.
chmod +x /usr/bin/pdf-compressor
β Ensures the binary is executable.update-desktop-database
β Updates the systemβs application database.

Setting up the correct permission for postinst
is important:

Step 9: Build & Install the deb package
After all the hard work, it's finally time to bring everything together. To build the package, weβll use dpkg-deb --build
, a built-in Debian packaging tool.
This command takes our structured pdf-compressor
directory and turns it into a .deb
package that can be installed on any Debian-based system.
If everything goes well, you should see output like:

Now, letβs install it and see our application in action!

sudo apt install -f
This installs pdf-compressor
onto your system just like any other Debian package. To verify, you can either launch it from the Applications menu or directly via terminal:

Final thoughts
Packaging a Python application isnβt as straightforward as I initially thought. During my research, I couldn't find any solid guide that walks you through the entire process from start to finish.
So, I had to experiment, fail, and learn, and thatβs exactly what Iβve shared in this guide. Looking back, I realize that a lot of what I struggled with could have been simplified had I known better. But thatβs what learning is all about, right?
I believe that this write-up will serve as a good starting point for new Python developers like me who are still struggling to package their projects.
That said, I know this isnβt the only way to package Python applications, there are probably better and more efficient approaches out there. So, Iβd love to hear from you!
Also, if you found this guide helpful, be sure to check out our PDF Compressor project on GitHub. Your feedback, contributions, and suggestions are always welcome!
Happy coding! π
I'm definitely not a nerd, perhaps a geek who likes to tinker around with whatever tech I get my hands on. Figuring things out on my own gives me joy. BTW, I don't use Arch.