It is very handy to have a chroot jail for testing code snippets, packages, releases. This is on your (Debian) dev box, where you may have multiple installed versions of related libs. Before promoting your new code to Test or Staging, it can be a time saver to first test it in a pristine environment that can’t be affected by files outside the ‘jail’. For example, I have several versions of Perl installed on my dev box and several versions of EV around the place. When testing something against EV I want to be sure I haven’t omitted any dependencies and to be sure I’m testing against exactly the version I’m expecting. You should treat the jail as throw-away; keep in mind that you can (and should) delete and build a fresh one whenever the mood takes you. There are many online notes about creating one, but it is still hard to find any that tell you how to get it ironed out easily, eg to avoid confusing sessions that are inside/outside the jail.

Install packages

mkdir -p /opt/jail/mojo
debootstrap wheezy /opt/jail/mojo

(and then wait a few mins while it downloads and installs). Then install locales.

chroot /opt/jail/mojo
dpkg-reconfigure debconf  # setting priority to 'medium'
vi /etc/apt/sources
apt-get update
apt-get install locales less vim rsync
locale-gen en_GB.UTF-8

That last line is to generate any locales that the previous line reported as missing; if you don’t see any such warnings (on the commandline) then none are needed.

Make it clear you are in jail

vi /etc/debian_chroot

giving it the jail name as content, in this example ‘Mojo’.

vi /etc/skel/.bashrc
vi /etc/bash.bashrc

removing all instances of “@\h“, eg by doing “:%s/@\\h//gc” with repeated presses of y

adduser --ingroup users --disabled-password --gecos 'test user,,,' tester
su - tester

and check that your commandline prompt shows the jail name and not the (parent) hostname. If you’re using an xterm you should also see its title change to something similar when you ‘sub user’ to ‘tester’. The remaining step for this section is to do likewise for ‘root’. The simplest way to do that is to copy the xterm lines from /etc/skel/.bashrc so that /root/.bashrc now has

case "$TERM" in
  PS1="\[\e]0;${debian_chroot:+($debian_chroot)}\u: \w\a\]$PS1"

Now open a new xterm and test both user envs

chroot /opt/jail/mojo
su - tester

checking that in both cases the xterm title and the commandline prompt are clearly different from those of the (parent) host.

(The rest of these notes are standard fodder for getting processes to work nicely.)

Mount Parts of Host System

Before installing more packages or running processes, you’ll need to integrate /proc
In /etc/fstab of the host box, I have a section for each jail

/dev/pts /opt/jail/mojo/dev/pts none bind 0 4
proc     /opt/jail/mojo/proc    proc defaults 0 4
sysfs    /opt/jail/mojo/sys     sysfs defaults 0 4

and then mount them manually (again as ‘root’ in the host box)

mount /opt/jail/mojo/dev/pts
mount /opt/jail/mojo/proc
mount /opt/jail/mojo/sys

Fake your mtab

You’ll find that df fails because the chroot has no /etc/mtab. Some people are advocating cat /proc/mounts >/etc/mtab but that is wrong, the partitions inside the chroot are in general completely different to those outside. In my case I give the missing file just one line

rootfs / rootfs rw 0 0

which does all that I want.

Set your timezone

You can manipulate /etc/timezone and /etc/localtime yourself, but the easiest way is to

dpkg-reconfigure tzdata

On a debian linux box the directory /var/cache/apt/archives gradually fills up with every .deb file you have ever installed or have ever downloaded with the option of installing. If a file corresponds to your currently installed version or is currently the most advanced version of that package you have available then you want to keep it, otherwise it’s redundant and may as well be deleted.

For example, let’s say I have 12 versions of bash sitting in that directory; the first 8 are previous versions, the 9th is the installed version, and the last 3 are versions I have downloaded but not gotten to the point of actually installing. In that case I want to keep the 9th and 12th files and delete the other 10.

Here is a perl script that will do exactly that. You could have a nightly script that did

apt-get update
apt-get upgrade --download-only -qq

then ran the following clean up script, then emailed you the list of packages having upgrades available.


use strict;
use warnings;

use Dpkg::Version qw(version_compare);

my %installed = ();

eval {
    my $pid = open(STATUS, '/usr/bin/dpkg-query -l | /bin/grep ^i |')
        or die 'Failed to get package status feed';
    while (defined($_ = )) {
        if (/^\w\w\s+(\S+)\s+(\S+)\s/) {
            $installed{$1} = $2;
        else {
            die 'Unrecognised package status line';
if ($@) {
    die "Failed to build list of installed versions\n". $@;

my %candidate = ( %installed );

eval {
    my $archive_dir = '/var/cache/apt/archives';
    opendir(AVAIL, $archive_dir)
        or die 'Failed to read archive dir';
    while (defined(my $deb = readdir(AVAIL))) {
        chomp $deb;
        if ($deb =~ /^([^_]+)_([^_]+)_/) {
            my ($p, $v) = ($1, $2);
            $v =~ s/%3a/:/g;
            if (exists $candidate{$p}) {
                my $cmp = version_compare($candidate{$p}, $v);
                if ($cmp  0) {
                    # Found a non-maximal version
                    unlink $deb
                        unless $installed{$p} && $installed{$p} eq $v;
            else {
                $candidate{$p} = $v;
        else {
            warn "Ignoring unrecognised file ($deb)";
if ($@) {
    die "Failed to build list of available versions\n". $@;


When trying to install packages from a debian archive that’s had a significant update, you sometimes get the error: “WARNING: The following packages cannot be authenticated!”
It is easily remedied via:

apt-get update
apt-get install debian-archive-keyring
apt-get update

Whenever possible I try to stick to using the official debian-packaged distribution of a CPAN perl module, but occasionally that’s not possible, either because I need a fresher version or because nobody has packaged it for the official repos. There are three work-arounds I’m aware of…

I’ll put my favourite first: using Yes, by tweaking your /etc/apt/sources.list you have access to most of the CPAN modules you could want.

Second best (since it looks at dependencies too): using cpan2dist. However, the failures of trying to build CPANPLUS::Dist::Deb lead me to the first approach.

Third best (but a good start if you’re working on building a single properly-constructed debian package): using dh-make-perl.