
Understand the chroot/jail technique on Linux. Restricted access for your SSH users. Use Jailkit or the fuschlberger script!
Real-world use case
You need to restrict an SSH user to a specific scope: here's how to set up a chroot/jail on Linux.
Jailing a user
Shared projects can sometimes lead to giving access to a production server.
It's difficult to give full access to the system to an external company (confidentiality/security).
To address this issue, there's chroot/jail, or jailing a user inside a folder.
The complete view of the server's directory tree will no longer be available to this user.
Jailing them provides:
- Increased flexibility.
- Additional security.
- Easier access provisioning.
Creating a closed environment
Understanding the general steps in creating a chroot/jail is important:
- Creating a user on the system.
- Creating the jail directory's structure.
- Adding a command interpreter.
- Mounting devices (optional).
- Modifying certain "/etc/" files.
- Creating a so-called wrapper function.
- Adding file permissions.
- Adding extra commands.
For more information on step-by-step creation of a "chroot/jail" environment, see léa-linux.
This method is fairly long, so we'll instead use existing scripts.
The scripts we'll use are Jailkit and the fuschlberger script on Debian 7 x64.

The first is a turnkey script that's still actively developed and more advanced, while the second is aging but works just as well, though with more difficulties on the 64-bit version.
More information on the official website of jailkit as well as the fuschlberger website.
The Jailkit script
Jailkit is a maintained script that lets you automate building a jail.
We can add one or more users to it in order to restrict them.
Download the script with "wget":
wget http://olivier.sessink.nl/jailkit/jailkit-2.17.tar.gz
Extract the file:
tar xvzf jailkit-2.17.tar.gz
Head to the folder:
cd jailkit-2.17
Run the following command:
./debian/rules binary
=> make[1]: leaving directory "/root/jailkit-2.17"
Exit the current directory:
cd ..
Start installing Jailkit:
dpkg -i jailkit_2.17-1_amd64.deb
Notice that new commands are now available: try running: "jk_"
jk_addjailuser jk_chrootlaunch jk_cp jk_jailuser jk_lsh jk_uchroot
jk_check jk_chrootsh jk_init jk_list jk_socketd jk_update
Create the jail directory:
mkdir /home/jail/
We need to give all permissions to "root":
chown root:root /home/jail/
Add programs to the jail:
jk_init -v /home/jail netutils basicshell jk_lsh ssh sftp editors
To add other programs, simply edit the following configuration file:
nano /etc/jailkit/jk_init.ini
Copying libraries is done with the "jk_cp" command, e.g. with "mysql":
jk_cp -j /home/jail/ /usr/bin/mysql
For information, here's how to display a program's libraries:
ldd /usr/bin/mysql
If you want to use mysql inside your jail:
mount --bind /var/run/mysqld/ /your/jail/var/run/mysqld/
Create the user who will be "chrooted" in their jail:
adduser jeremie
=>Adding user `jeremie' ...
Adding new group `jeremie' (1001) ...
Adding new user `jeremie' (1001) with group `jeremie' ...
Creating home directory `/home/jeremie'...
Copying files from `/etc/skel'...
Enter new UNIX password:
Retype new UNIX password:
passwd: password updated successfully
Changing the user information for jeremie
Enter the new value, or press Enter for the default
Full Name []: Jérémie Kassianoff
Room Number []:
Work Phone []:
Home Phone []:
Other []:
chfn : name contains non-ASCII characters: Jérémie Kassianoff
Is the information correct? [Y/n]Y
We add the user to the jail with the following command:
jk_jailuser -m -j /home/jail/ jeremie
Edit the file of existing users on the "jail" system:
nano /home/jail/etc/passwd
Find your user and change your "shell":
jeremie:x:1001:1001:,,,:/home/jeremie:/bin/bash
You can now log in as your user:
su - jeremie
Show the jail's root:
ls /
bin dev etc home lib lib64 usr
The jailkit introduction is complete.
The fuschlberger script
The fuschlberger script is fairly old (2008) but it still works very well.
We'll get it running on Debian 7 64-bit.
Before anything else, make sure you have the following packages installed:
debianutils coreutils
Download the script with "wget":
wget http://www.fuschlberger.net/programs/ssh-scp-sftp-chroot-jail/make_chroot_jail.sh
Make the script executable:
chmod 770 make_chroot_jail.sh
Run the script (simplified version):
make_chroot_jail.sh jeremie
By default the jail will be located at "/home/jail", if you want to change the directory:
make_chroot_jail.sh jeremie [/path/shell] [/path/jail]
If you run the script, you'll most certainly get an error on the 64-bit version.
Now we're going to start changing certain values in the script.
Errors on Debian 7 X64
The first time you run the script (x64) you probably saw errors appear.
To fix the first error (line 406 & 407), you need to edit the fuschlberger script:
nano make_chroot_jail.sh
Then find the following two lines:
TMPFILE1=`mktemp` &> /dev/null || TMPFILE1="${HOME}/ldlist"; if [ -x ${TMPFILE1} ]; then mv ${TMPFILE1} ${TMPFILE1}.bak;fi
TMPFILE2=`mktemp` &> /dev/null || TMPFILE2="${HOME}/ldlist2"; if [ -x ${TMPFILE2} ]; then mv ${TMPFILE2} ${TMPFILE2}.bak;fi
You need to remove "/dev/null" like this:
TMPFILE1=`mktemp` || TMPFILE1="${HOME}/ldlist"; if [ -x ${TMPFILE1} ]; then mv ${TMPFILE1} ${TMPFILE1}.bak;fi
TMPFILE2=`mktemp` || TMPFILE2="${HOME}/ldlist2"; if [ -x ${TMPFILE2} ]; then mv ${TMPFILE2} ${TMPFILE2}.bak;fi
The second problem is in the library paths:
elif [ "$DISTRO" = DEBIAN ]; then
cp /lib/libnss_compat.so.2 /lib/libnsl.so.1 /lib/libnss_files.so.2 /lib/libcap.so.1 /lib/libnss_dns.so.2 ${JAILPATH}/lib/
else
cp /lib/libnss_compat.so.2 /lib/libnsl.so.1 /lib/libnss_files.so.2 /lib/libcap.so.1 /lib/libnss_dns.so.2 ${JAILPATH}/lib/
fi
We end up with paths for the x86 version, so we need to adapt them to our x64 system:
elif [ "$DISTRO" = DEBIAN ]; then
cp /lib/x86_64-linux-gnu/libnss_compat.so.2 /lib/x86_64-linux-gnu/libnsl.so.1 /lib/x86_64-linux-gnu/libnss_files.so.2 /lib/x86_64-linux-$
else
cp /lib/x86_64-linux-gnu/libnss_compat.so.2 /lib/x86_64-linux-gnu/libnsl.so.1 /lib/x86_64-linux-gnu/libnss_files.so.2 /lib/x86_64-linux-$
fi
Once the issues are fixed, rerun the script with the command:
make_chroot_jail.sh jeremie
Then, the command's output will show:
Release: 2008-04-26
Am I root?
OK
Checking distribution...
Supported Distribution found
System is running Debian Linux
Checking for which...
OK
Checking for chroot...
OK
Checking for sudo...
OK
Checking for dirname...
OK
Checking for awk...
OK
Subsystem sftp /usr/lib/openssh/sftp-server
-----------------------------
The file /bin/chroot-shell exists.
Probably it was created by this script.
Are you sure you want to overwrite it?
(you want to say yes for example if you are running the script for the second
time when adding more than one account to the jail)
(yes/no) -> yes
Modifying /etc/sudoers
Adding User "jeremie" to system
Enter new UNIX password:
Retype new UNIX password:
passwd: password updated successfully
Adding User jeremie to jail
Copying necessary library-files to jail (may take some time)
Copying files from /etc/pam.d/ to jail
Copying PAM-Modules to jail
If you browse the jail folder:
ls -al /home/jail
You'll see the work done by the fuschlberger script.
Try logging in with the user you previously created:
su - jeremie
"su: module is unknown" error:
su: Module is unknown
The solution I found is to edit the chroot-shell file:
nano /bin/chroot-shell
Initially you'll find this inside:
#!/bin/bash
/usr/bin/sudo /usr/sbin/chroot /home/jail /bin/su - $USER "$@"
The change to make:
#!/bin/bash
sudo /usr/sbin/chroot /home/jail /bin/bash
Then you need to rerun the command:
su - jeremie
You should now be logged in with no errors, and you're indeed inside your jail.
However, you have a restricted list of commands, to add more: edit the script!
nano /usr/local/sbin make_chroot_jail.sh
Search for the "APPS" line with "ctrl + w" and add the path of the commands you want.
elif [ "$DISTRO" = DEBIAN ]; then
APPS="/bin/bash /bin/crontab /bin/vim /bin/mysql /bin/hg /bin/hg-ssh /usr/bin/clear /usr/bin/ncurses5-config /bin/nano /bin/cp /usr/bin/ /bin/ls /bin/mkdir /bin/mv /bin/rm /bin/rmdir /bin/sh /bin/ping /bin/su /usr/bin/groups /usr/bin/id /usr/bin/rsync /usr/bin/ssh /usr/bin/scp /sbin/unix_chkpwd"
Then, you need to update your jail with the script:
make_chroot_jail.sh update
Also, if you want to resolve domain names you'll need to add the DNS library:
cp /lib/x86_64-linux-gnu/libnss_dns.so.2 /home/jail/lib
This script is a bit dated but makes for a good base to get started with jail/chroot.
Conclusion
I've compared here two methods for jailing an SSH user on Linux: the Jailkit script, more recent and maintained, and the fuschlberger script, older but still functional with a few adjustments for the 64-bit version. These chroot/jail techniques let you provide restricted access to a production server without exposing its entire directory tree, which strengthens security and confidentiality during external collaborations. One point to watch: the list of commands available inside the jail should be adjusted sparingly so as not to recreate an environment that's too open.
Personally, I stopped there and didn't look into the other possible options.
You now know how to use these two scripts! Share your feedback in the comments section.
