Watch on YouTube:

The Installer Trifecta Series


If you're the intelligent and impatient type:

Skip down to Building the deb and see the final steps and then glance back up at Getting Started to see the directory structure.

Why .deb?

Two words: Double Click.

Although I could cite angry flame wars on the topic of installing via curl | bash is evil, I like that method just fine. In reality, it's just as secure as a foreign .deb. However, from the end-user perspective, a double-click installer is "more legit".

The best news is that Debian installers (.debs) are actually incredibly simple (vim, tar, and ar are all you need) and the Linux (GNU / OpenDesktop, actually) desktop architecture is also really coherent.

Although I don't strictly follow the debian standards with my example installer, it gets the job done without bothering the user and without using the more robust (read complicated) canonical debian tools.

Getting Started

The demo app I'm packaging in this tutorial is HelloNode

The basic outline of the filesystem structure I used is like so

        /control                                      # required for .debs
        /postinst                                     # preinstall script
        /preinst                                      # postinstall script
        /prerm                                        # preuninstall script

Those file are needed exclusively for the .deb and will not be installed. They will tard up as control.tar.gz before the final build step.

        /etc/init/hello-node.conf                     # upstart script
            /applications/hello-node.desktop          # desktop icon
            /doc/hello-node/copyright                 # required for .debs
            /doc/hello-node/README                    # required for .debs
            /icons/hicolor/48x48/apps/hello-node.png  # desktop icon icon

Everything under sysroot (which is the name I arbitrarily gave this folder) will be packaged to install to /, so the directory structure is exactly as it will be installed. No muss, no fuss, no guessing.

The total size of these files will be caculated by du -s and then put in control as Installed-Size just before getting tard up as data.tar.gz for the final build step.

I've created a bash script that packages the app for me very quickly.

The first thing I do is copy deb-src to /tmp/deb-src for a fresh start

rm -rf /tmp/hello-node-deb-src
rsync -a ~/HelloNode/debinstall/deb-src/ /tmp/hello-node-deb-src/

App Files

Next I just throw all of the files for my app into /opt/hello-node because I didn't organize it in unix-proper fashion before embarking on this endeavor.

rsync -a ~/HelloNode/HelloNode/ /tmp/hello-node-deb-src/sysroot/opt/hello-node/

That's it. Done.

System Service

The upstart file for this project is a very basic one that just spawns the server as soon as the filesystems are mounted and again if it happens to crash.


description "Hello Node System Service"

start on filesystem
stop on runlevel [06]

console output

  node /opt/hello-node/bin/server.js
end script

Desktop Icon

The desktop icon is installed at the system level and will show up in menus and search.

You don't generally need a desktop icon for a system service, but I decided it would be cool to have one that opens the app in Chrome's App Mode.


[Desktop Entry]
Name=Hello Node Browser
Comment=Open Hello Node in Chrome
Exec=google-chrome --app="http://localhost:5566#%U"

A cool thing here is that if you were to drag an mp3 onto the icon, it would open the url with the path to the mp3 as the anchor - so you could actually use your service to find the mp3 on the local system and play it with the html5 api. Cool, huh?

The icon for the icon is /usr/share/icons/hicolor/48x48/apps/hello-node.png

Debian metadata

control is just super basic metadata

Package: hello-node
Version: 1.0-1
Section: base
Priority: optional
Architecture: i386
Installed-Size: SIZE
Maintainer: AJ ONeal <>
Description: HelloNode! The installable NodeJS System Service
 Let's you install a nodejs app as a service, just to see how it feels.

In I run sed to replace SIZE with the size of /tmp/hello-node-deb-src/sysroot as per du -s.

Now Here's where I do a little bit of dirty trickery: With the preinstall script I install node (the wrong way) and with the postinstall script I install google-chrome (the nearly right way)

Aside from that, postinstall starts the upstart system service and prerm stops it. Technically prerm should also remove the files (node and count.db) that I created that were not part of data.tar.gz

Building the deb

A few other tricks that does are to change the file ownership to root:root, fix permissions to 0755 for regular dirs and executables, and 0644 for regular files. As stated previously, it also updates Installed-Size in control.

The nitty-gritty aside, it's basically just doing this

pushd deb-src

pushd sysroot/
tar czf ../data.tar.gz *

pushd DEBIAN/
tar czf ../control.tar.gz *

echo 2.0 > debian-binary
ar r ../hellonode-1.deb debian-binary control.tar.gz data.tar.gz

By AJ ONeal

If you loved this and want more like it, sign up!

Did I make your day?
Buy me a coffeeBuy me a coffee  

(you can learn about the bigger picture I'm working towards on my patreon page )