Skip to content
A GNU/Linux specific toolkit for easily making light filesystems for namespaced chroots.
Shell Makefile
Branch: master
Clone or download
Fetching latest commit…
Cannot retrieve the latest commit at this time.
Type Name Latest commit message Commit time
Failed to load latest commit information.
busybox @ 0f1369f
musl @ ea9525c
openssh @ cdf1d0a
zlib @ cacf7f1


JailTools - helper script for creating jails

What is JailTools?

Jailtools is a toolkit for easily creating a jail for your services using chroot and namespaces. It provides a slim OS-level virtualization solution for the GNU/linux operating system.


JailTools makes it easy to create chroots for any purpose. It has tools for copying applications and libraries to the jail, so as to also copy the shared objects they depend on to run correctly. JailTools creates a minimal filesystem (about 6MB in size) which is meant to include only the bare minimum for applications or libraries to do their job. This way, in case the service is compromized, the adversary will only get access to that filesystem rather than the host system directly.


Jailtool scripts

There are 3 useful scripts :

  1. jailtools - jt

    jailtools (jt is a symbolic links to jailtools) is a super script that will be used to call other scripts and
    do the various tasks related to jailTools directories.
    This is the only script you will ever need to use.
    'jailtool new' and 'jailtool cp' call the following scripts:

    Used to create new jails (as the name implies). (internal use only, use 'jt new' instead)

    Used to copy binaries or libraries to the jail and it does
    it's best to copy dependencies (shared objects) with it too. (internal use only, use 'jt cp' instead)

Compilation and Installation

Quick steps :

  1. install requirements: git, gcc, GNU make

  2. get the source code with 'git clone'

  3. 'make' will download, configure and compile musl and busybox.

  4. install the super script with

Elaborated steps :

Step 1:

Get jailTools from the git repository:

git clone

This will download the repository to the directory 'jailTools'.

Step 2:

The project relies on musl (libc) and busybox. The latter provides the underlying filesystem shell and commands inside each jail. Both of these dependencies are automatically cloned by the Makefile process. We don’t use already installed versions because we want statically linked versions of both of these to save space.

To compile, just run 'make'. This will compile musl and then use it to statically link busybox.

Step 3:

The installation script '' will copy the super script 'jailtools' to a location of your choice. It only installs the super script, not the whole jailTools directory. It sets up the super script with the path of the project’s git repository directory so it could stay in any place you want. If you decide to change the location of the jailTools directory just redo this step to update the super script with the new location.

If you want to use jailTools for your user only, just clone the git repository, compile and do this:

sh ./ ~/bin

This will install the super script inside your user’s bin directory. Make sure that you have ~/bin in your "PATH" environment variable.

From now on we will reference the super script jailtools as just jt in this text. You can however use jailtools or jtools if you prefer.

System wide installation:

In case you want to make the project available for all users on the system. These are the steps to do so.

It is currently not possible to start jails or access them in any matter that does not require super user privileges. This means that users would need root access in order to fully use jails created with jailTools. The only way an unprivileged user could access a started jail is through network services like telnet or ssh.

Move jailTools folder to '/opt':

sudo mv jailTools /opt/jailTools

And change ownership to root:

sudo chown root:root -R /opt/jailTools

From inside /opt/jailTools, install the super script to '/opt/bin':

sudo sh ./ /opt/bin
This will install the super script to the path /opt/bin. The script '' needs to be executed from the location where the jailTools scripts reside so the references are done correctly inside the super script 'jailtools'.


Here is a list of available commands when calling jailtools:

  • new

    creates a new jail directory
  • cp

    copy files or directories (with their shared object dependencies) into the jail
  • start, stop, daemon, shell All take the <path> argument

    these are per jail specific commands. You can provide these with a single argument which is the path of the jail to run this command.

Creating a new jail

Synopsis :

jt new <path and name> <optional jail's main username> <optional jail's main group>

Both internal username and group are used inside the jail itself, and will be added to /etc/\{passwd,shadow\} and /etc/group respectively, inside the chroot. The main user will be exactly the same UID as the user that created the jail, same goes for the group. If they are not explicitely added, they will be created with the same name as the jail.

The jail name is initially the directory in which the jail resides. That name can be changed inside the configuration file

Example :

jt new /path/to/example foo bar

This will create a new directory called example containing the jail and once running, the user’s UID and GID will be mapped to foo and bar respectively. Inside the jail directory /path/to/example there are 3 notable scripts : . (don’t run this directly, use the super script jailtools) . (where you place your configuration and custom scripting) . (this contains the files which are copied by the 'cp/cpDep' command so you can reproduce and update your jail)

The script is not meant to be edited. Make your changes in the script

As is, the jailTools creates a jail with only basic apps and a shell (provided by busybox).

Jail commands

A newly created jail includes 3 ways to start the chroot :

  • sudo jt start

    This starts the jail and provides you with an interactive shell inside it.
You usually want to make this start your programs automatically. This is mostly for applications like firefox, games or anything that you use directly.
  • sudo jt shell

    If the jail is not already started, this behaves exactly like the command 'start'.
    But when the jail is already running, this provides a shell inside it.
  • sudo jt daemon

    This starts the jail in daemon mode. When started, the jailed is
    placed in the background and puts you back into the calling shell.
    It will stay running even after you close your terminal.
    The only way to gain access is through the shell command or,
    if available, network shell providers like ssh or telnet.
You usually want to make this start your services automatically. This is mostly for starting servers and any application that run in the background.

How to install applications in jail

To add more applications to the jail, use jailtools’s cp command.

Here we show how to copy the application strace to the jail :

jt cp /usr/bin /usr/bin/strace    # this is done inside the jail directory itself

Here’s what the arguments mean :

  • /usr/bin

    The first path is actually the destination path *inside* the jail that you want
    to copy your binary to. We could have put /bin if we wanted or any path you
    want (as long as you take care of setting the PATH correctly in the jail).
  • /usr/bin/strace

    This is the path on your base system for the strace application, which, in our
    case is in our /usr/bin directory.

cp will check all shared object dependencies that strace requires to run and copy them along with the binary itself. This way, you will be able to run the application without doing any more work than that.

Certain applications also requires specific devices (in /dev) and/or directories to be present, the command cp can not provide those. You will need to figure these either from the manual of these programs or by using the strace program (we purposefully shown how to copy it to a jail for this reason).

How to Customize the jail

There are 4 vectors of customization for jails. Each in their own section in

They are :

  1. The configuration variables/flags

    These are used to toggle features provided in the jail and set various values
    for configurating, for example, the firewall.
  2. The mount points

    These are used specifically to mount external directories inside the jail itself,
    making the files/directories accessible to the jailed applications. There are 3 kinds
    of mount points each with their section.
  3. the functions

    These are used to customize firewall rules, mount extra files (those that are out of
    scope of the mount points section) and set up your own start instructions so the
    jail can run the service you want.
  4. CUI commands

    Use this to set up your own commands.


Tips and Tricks

shorewall specific

how to open a port

Shorewall custom INBOUND configuration : in, in the function prepCustom, add these lines :

        cat >> $firewallPath/rules.d/$bridgeName.rules << EOF
ACCEPT  fw      $firewallZoneName       tcp     10922
DNAT    lan     $firewallZoneName:$ipInt tcp    10922

this is an example where we open the port 10922 for access from the localhost and also the lan network. Notice that for the lan network (external to the main host) we have to use a DNAT to our internal chroot.

how to prepare shorewall for jailTools

With shorewall, jailTools adds it’s changes to a directory ending with '.d' like 'rules.d'. These are not standard issue with shorewall, to make use of their content, it is necessary to add a single line in all the configuration files that potentially will get extra configurations in these. (As of this writing, these configuration files need modifications : zones, interfaces, policy and snat, we create one for rules too strictly as a service for the user as jailtools does not add anything to it directly).

Here’s how you can actually make your configuration file load all the content of the 'x.d' directory (for example here zones → zones.d).

SHELL cat /etc/shorewall/zones.d/*.zones 2> /dev/null || true

And that’s it, this loads all the .zones files in zones.d and the last part of the instruction is to ensure everything works correctly even if the directory is empty.

It’s exactly the same line for all the other configuration files except the 2 occurrences of 'zones' which need to be changed to the configuration’s name : like rules.d/*.rules

Noteworthy : in pretty much all configuration files you can add this line at the end, except for policy. This one will need to have the inclusion before the last line that rejects everything.

You can’t perform that action at this time.