Jailkit howto - creating an SSH only shell in a chroot jail


We want to create an account that can only do ssh in a chroot. This is for example useful on a firewall machine. Users can login to the firewall, but the only thing they can use the account for is to login to the next machine. Possibly the firewall machine only allows RSA key authentication, and the next machine allows only password authentication. Such a setup requires double authentication for a login.

client+ssh --> firewall+ssh --> destination

There is a shell needed in the jail, because some program is required to start the ssh binary. We will look at a normal shell (bash), and the jailkit limited shell (jk_lsh).


Suppose the jail is /home/chrootusers and the user we want to jail is user john in group users. User john wants to login to our filewall (called firewall) using ssh, and then continue to another server (called realserver).

Ssh in a chroot jail

There are several requirements to get ssh working in a jail. First you need the /usr/bin/ssh binary. It needs two devices, /dev/urandom and /dev/tty. Obviously it needs several libraries as well, you can find them using ldd /usr/bin/ssh. The latest version of jk_init can do most of these things:

jk_init -v -j /home/chrootusers ssh

Note that the jk_init.ini file in the Jailkit tarball has defaults for Debian and Ubuntu. If you use jk_init on other operating systems you may need to use a different jk_init.ini file, or update the file locations in jk_init.ini yourself.

Getting the user into the chroot jail

To jail user john, he should have jk_chrootsh as shell in /etc/passwd. The entry in /etc/passwd should look like:


Inside the jail, user john needs to get his normal shell. We will discuss both bash and jk_lsh.

Bash in the chroot jail

Copy bash and it's libraries into the chroot jail using jk_cp:

jk_cp -v -f /home/chrootusers /bin/bash

Now edit /home/chrootusers/etc/passwd and make sure it contains a line like:


and make sure the group exists in /home/chrootusers/etc/group like this:


Now try to login using ssh john@firewall, and look for any errors in /var/log/auth.log.

Now user john can start his ssh session to john@realserver:

ssh john@realserver

We can also do this in one go, by giving the second commandline as argument to the first commandline. This only works if the first commandline uses the option -t like this:

ssh -t john@firewall ssh john@realserver

Jk_lsh in the chroot jail

Copy jk_lsh and it's libraries into the chroot jail, this can be done using jk_cp or with jk_init:

jk_init -v -f /home/chrootusers jk_lsh

Now edit the /home/chrootusers/etc/passwd file, it should show something like:


jk_lsh can do some logging, but in order to do so it needs to have a /dev/log socket. This can be done using syslog, or by the jk_socketd. Edit /etc/jailkit/jk_socketd.ini and make sure it shows a section like:

[/home/chrootusers/dev/log] base = 1024 peak = 10240 interval = 2

Now restart jk_socketd, for example, kill it and restart it:

killall jk_socketd ; jk_socketd

Any jk_socketd errors are logged into /var/log/daemon.log. If you try to login right now, you will find an error in /var/log/auth.log saying that john is not allowed to run a regular shell. And that is true, he's only allowed to do ssh, right!

To allow john to use ssh, we have to allow that, so we edit /home/chrootusers/etc/jailkit/jk_lsh.ini so it should allow ssh:

[john] paths= /usr/bin executables= /usr/bin/ssh

Now we can start ssh, but only ssh, and we do this by starting ssh immediately from the first ssh commandline. As with the previous example, also in this case we need to pass the -t option to the first ssh command:

ssh -t john@firewall ssh john@realserver

If your configuration is correct, you should get both logins now, otherwise look for errors in /var/log/daemon.log or /var/log/auth.log.

Getting X forwarding to work trough the jail.

Ssh can do X forwarding. It creates a fake X-server and every X-client program can send it's data to this fake server, and ssh will forward it to the real server. Because we use two ssh sessions, the first ssh session needs to pass the X-client data to the second ssh session. This needs to be enabled on the ssh server, edit /etc/ssh/sshd_config and restart the ssh server afterwards, the file should have this line enabled:

X11Forwarding yes

There are also some environment variables that need to be passed on. Normally jk_chrootsh blocks all environment variables, so we edit /etc/jailkit/jk_chrootsh.ini and make it look like:


The sessions use an authorization protocol, handled by the xauth program. That means that we need the xauth program inside the jail. The xauth program needs libraries, and these libraries or not in the standard directories, that means that we need to add /etc/ld.so.conf and /etc/ld.so.cache to the jail. The ssh client has the path hardcoded into the executable, usually this path is /usr/bin/X11/xauth. It also needs /dev/null. Luckily the jk_init program can take care of this:

jk_init -v -f /home/chrootusers/ xauth

The ssh program tries to start xauth using /bin/sh, so we have to create /bin/sh as a symlink to /usr/sbin/jk_lsh:

cd /home/testchroot mkdir bin ln /usr/sbin/jk_lsh bin/sh -s

Now ssh will try to start xauth using jk_lsh, so we have to allow that in the jk_lsh config file in the jail as well, edit /home/chrootusers/etc/jailkit/jk_lsh.ini and change it to this:

[john] paths= /usr/bin, /usr/bin/X11/ executables= /usr/bin/ssh, /usr/bin/X11/xauth

Now ssh with X-forwarding should be possible. Test it using:

ssh -X -t john@firewall ssh -X john@realserver

If your configuration is correct, you should get both logins now, otherwise look for errors in /var/log/daemon.log or /var/log/auth.log. Getting debug output from your ssh program can help as well, use the commandline:

ssh -X -v -t john@firewall ssh -X -v john@realserver


If you use procmail for email delivery, users can execute commands outside the jail using a .procmailrc in their homedir. You should use jk_procmailwrapper so users inside a jail cannot use mail delivery, or use aliases so procmail is not executed for these users.

To make things complete, we can edit the ssh server file /etc/ssh/sshd_config on the firewall and disable any password logins.

PasswordAuthentication no

Because user john cannot login to the firewall using a password anymore, the system administrator (you) should edit the /home/chrootusers/home/john/.ssh/authorized_keys file and add john his public key there.

We should also add this jail to the jk_check config file, and run jk_check from the cron daemon every night.