This post is about building a Debian package to deploy a Django application on a Debian server.
The package will take care of the following:
- Install application
- Web server configuration (in our case: Lighttpd with fastcgi)
- Init.d script to start/stop Django server
We will also use a debconf template to ask 1 question to the user to make our package more dynamic.
Let’s assume you have a Django application located in /usr/share/djangoapp . This is where you have settings.py, manage.py, views.py etc…
First thing, we need to create a folder debian and copy the Django app folder into it:
mkdir ./debian mkdir -p ./debian/usr/share/ cp -r /usr/share/djangoapp ./debian/usr/share/
We also need to create a folder names DEBIAN in debian/
mkdir ./debian/DEBIAN
DEBIAN files
This folder needs to contain the following files:
- control
- config
- conffiles
- templates
- postinst
- postrm
- preinst
- prerm
control
This is the most important file in a Debian package. It gives information on the package itself along with some dependencies. In our case, it looks like this:
Package: djangoapp Version: 0.1-1 Section: devel Priority: optional Architecture: all Depends: python, python-django, python-flup, debconf, lighttpd Maintainer: Laurent Luce <laurent@tomnica.com> Description: short description long description
Depends consists of a list of packages required for our package to run properly.
config
config is a script responsible for asking questions to the user before the package gets installed. In our case, we will ask one simple question: what is your full name?
#!/bin/sh -e # Source debconf library. . /usr/share/debconf/confmodule # server type? db_input critical djangoapp/username || true db_go
As you can see, you need to include debconf confmodule to add configuration support. Our question is critical.
Wait a minute, where is the question definition? It is defined in the templates file
templates
This is where we define our question: string type.
Template: djangoapp/username Type: string Description: Username: This package requires your full name.
conffiles
This file contains the configuration files generally located under /etc . We add our Django start script and the lighttpd configuration file.
/etc/init.d/django /etc/lighttpd/lighttpd.conf
preinst
This script is run before the package gets installed.
#!/bin/bash set -e # stop django server if [ -f /etc/init.d/django ] then invoke-rc.d django stop fi
postinst
This script is run after the package is unpacked.
#!/bin/sh set -e # Source debconf library. . /usr/share/debconf/confmodule db_get djangoapp/username username="$RET" # do what you want with this username # register django update-rc.d django defaults 90 >/dev/null # start django invoke-rc.d django start db_stop
postrm
This script is run after the package is removed.
#!/bin/bash set -e if [ "$1" = "purge" -a -e /usr/share/debconf/confmodule ]; then # Source debconf library. . /usr/share/debconf/confmodule # Remove my changes to the db. db_purge fi if [ "$1" = "remove" ]; then # Source debconf library. . /usr/share/debconf/confmodule # remove Django start script update-rc.d -f django remove # Remove my changes to the db. db_purge fi
prerm
This script is run before the package is removed.
#!/bin/bash set -e # stop django server invoke-rc.d django stop
Web server configuration
Here is what needs to be modified in the web server configuration (in our case, lighttpd.conf):
mod_fastcgi needs to be added to the server modules.
The Django server will be running on port 3033 so we need to specify the connection here:
fastcgi.server = ( "/djangoapp.fcgi" => ( "main" => ( # Use host / port instead of socket for TCP fastcgi "host" => "127.0.0.1", "port" => 3033, "check-local" => "disable", )) )
Django init.d script
Now is time to add our Django start/stop script:
#! /bin/sh ### BEGIN INIT INFO # Provides: FastCGI servers for Django # Required-Start: networking # Required-Stop: networking # Default-Start: 2 3 4 5 # Default-Stop: 0 1 6 # Short-Description: Django FastCGI # DJANGO_SITE="djangoapp" SITE_PATH=/var/www RUNFILES_PATH=$SITES_PATH/tmp HOST=127.0.0.1 PORT_START=3033 RUN_AS=www-data set -e PATH=/usr/local/sbin:/usr/local/bin:/sbin:/bin:/usr/sbin:/usr/bin DESC="Django FastCGI" NAME=$0 SCRIPTNAME=/etc/init.d/$NAME # # Function that starts the daemon/service. # d_start() { # Starting all Django FastCGI processes echo -n ", $DJANGO_SITE" if [ -f $RUNFILES_PATH/$DJANGO_SITE.pid ]; then echo -n " already running" else start-stop-daemon --start --quiet \ --pidfile $RUNFILES_PATH/$DJANGO_SITE.pid \ --chuid $RUN_AS --exec /usr/bin/env -- python \ $SITE_PATH/$DJANGO_SITE/manage.py runfcgi \ host=$HOST port=$PORT \ pidfile=$RUNFILES_PATH/$DJANGO_SITE.pid fi } # # Function that stops the daemon/service. # d_stop() { # Killing all Django FastCGI processes running echo -n ", $DJANGO_SITE" start-stop-daemon --stop --quiet --pidfile $RUNFILES_PATH/$SITE.pid \ || echo -n " not running" if [ -f $RUNFILES_PATH/$DJANGO_SITE.pid ]; then rm $RUNFILES_PATH/$DJANGO_SITE.pid fi } ACTION="$1" case "$ACTION" in start) echo -n "Starting $DESC: $NAME" d_start echo "." ;; stop) echo -n "Stopping $DESC: $NAME" d_stop echo "." ;; restart|force-reload) echo -n "Restarting $DESC: $NAME" d_stop sleep 1 d_start echo "." ;; *) echo "Usage: $NAME {start|stop|restart|force-reload}" >&2 exit 3 ;; esac exit 0
This script needs to be placed in ./debian/etc/init.d/
You will also need to create a link from /var/www/djangoapp to /usr/share/djangoapp
changelog, changelog.Debian and copyright
Those are required for Debian packages:
changelog
djangoapp (0.1-1) unstable; urgency=low * Initial release. + Initial package -- Laurent Luce <laurent@tomnica.com> Fri, 01 Jan 2010 00:00:00 +0000
In our case, changelog.Debian is identical to changelog.
copyright
DjangoApp Copyright: bla bla 2010-01-01 The home page of xxx is at: http://www.xxx.com Copyright xxx 2010
We need to place those files properly:
mkdir -p ./debian/usr/share/doc/djangoapp cp changelog changelog.Debian copyright ./debian/usr/share/doc/djangoapp/ gzip --best ./debian/usr/share/doc/djangoapp/changelog gzip --best ./debian/usr/share/doc/djangoapp/changelog.Debian
Build package
We need to fix the permission of our package files:
find ./debian -type d | xargs chmod 755
We build the package and verify it:
fakeroot dpkg-deb --build debian mv debian.deb DjangoApp_0.1-1_all.deb lintian DjangoApp_0.1-1_all.deb
Our package is now ready to be deployed.
If you enjoyed this article, check out my web app Gourmious and discover and share your favorite restaurant dishes.
Comments
Thank you very much for this tutorial!
oh my “bip” this tut article is ‘bip’ing awesome! i creating a deb package, and that’s ‘bip’ing easy! tnx 😡
Hello, thanks for the explaination, but can you please add more details how to do the webserver configuration? I think there is missing one step, cant figure out where put make the lighttpd.conf modifications. Greetings Willi
You need to do the same as for /etc/init.d/django. e.g /etc/lighttpd/lighttpd.conf. I updated the tutorial to reflect that.
Thanks a lot for such detailed instruction!
hello, and thanks for your tutorial. I try to build a Debian package with simple files : – a JAVA app (.jar) – launchers in /usr/bin/myapp (just a simple Bash script) – autostart for X sessions : /etc/xdg/autostart/myapp.desktop – some files like icons that go to /usr/share… – modifying Gnome and KDE menus to insert myapp So i don’t have sources to compile. The weird thing is that on a parc with near 200 PC, my package installed successfully on all. But some PC don’t have anything except the directory /opt/myapp where the JAVA files are in. I don’t understand how to force it to copy files to /etc/… and /usr… Do you have some ideas about that please ? I’m running Debian testing (Squeeze).
@survietamine I am a bit confused, do you mean those machines don’t have the folders /etc, /usr etc… or do you mean your app files are not copied in those folders? The Debian file conffiles allows you to specify which files are configuration files and any files under /etc/ should be added to that file. For example, this is where I specified /etc/init.d/django which the script to start/stop the Django server instances.
Comments are closed.