Jailkit howto - creating an sftp/scp-only shell in a chroot jail


We want to create an account that can do sftp and scp only, and the account should be restricted to uploading/downloading files that are in a chroot jail.


Assume the account on machine ftpserver is for user mike in group users, and the jail is /srv/sftpjail.

sftp-server and scp in a chroot jail

First we need to copy scp and sftp-server into the jail. These binaries needs some libraries, you can find them using ldd /usr/bin/scp, we have to copy those as well. This can be done automatically with jk_cp, or it can be done automatically with jk_init with a well configured jk_init.ini

The initial jk_init.ini has defaults for 32bit Debian and Ubuntu. On other systems these defaults can be wrong. Especially the location of the sftp-server binary is different on almost all Linux distributions and other operating systems. If you are going to use jk_init for automatic jail setup, make sure you review jk_init.ini!

If jk_init.ini is correct for your system, simply run:

jk_init -v -j /srv/sftpjail sftp scp

Inside the jail, user mike needs to get a shell to execute sftp or scp, and only sftp or scp. We use jk_lsh to do this. 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 -j /srv/sftpjail jk_lsh

Jail the user

To jail user mike, he should have jk_chrootsh as shell in /etc/passwd. This shell will chroot to the directory, drop privileges and execute the real shell.

jk_jailuser -m -j /srv/sftpjail mike

Alternatively you can edit the files manually. The entry in /etc/passwd should look like:


and /srv/sftpjail/etc/passwd should look like:


Passing logs to the real system with syslogd

jk_lsh can do some logging, but in order to do so it needs to have a /dev/log socket. And since it runs inside the jail, it cannot write to the real /dev/log socket. You can add home/jail/dev/log to the syslog configuration file. Add "-a /srv/sftpjail/dev/log" to the syslogd options (every distribution and operating system has it's own way to do this, so this is not explained in this howto). For syslogd-ng you can specify extra sockets in it's config file.

Passing logs to the real system with jk_socketd

jk_socketd allows you to limit the amount of logging coming from the jail, so if you want to restrict users such that they cannot overflow your logs you can use it. Edit /etc/jailkit/jk_socketd.ini and make sure it shows a section like:

[/srv/sftpjail/dev/log] base = 1024 peek = 10240 interval = 2

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

killall jk_socketd ; jk_socketd

Any jk_socketd errors are usually logged into /var/log/daemon.log. Any messages from jk_chrootsh and jk_lsh are usually logged to /var/log/auth.log. If you try to login right now, you will find an error in the logs saying that mike is not allowed to run an interactive shell. And that is true, he's only allowed to do sftp or scp.

Executing sftp or scp, and only sftp or scp

To allow mike to use sftp and scp, we have to allow that, so we edit /srv/sftpjail/etc/jailkit/jk_lsh.ini so it allows sftp and scp:

[mike] paths= /usr/bin, /usr/libexec/openssh/ executables= /usr/bin/scp, /usr/libexec/openssh/sftp-server


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.


Some ssh servers are configured to use the internal sftp server. If /etc/ssh/sshd_config contains the line Subsystem sftp internal-sftp it will not start a shell, and thus bypass jk_chrootsh. You must change the configuration to point to the external sftp server such as Subsystem sftp /usr/libexec/openssh/sftp-server (depending on your Linux distribution the path to sftp-server is different).

If you get a connection, but immediately after that you are disconnected again, usually your jk_lsh is not configured as expected. Look in the logs for clues. On systems with journalctl you can enter journalctl|grep jk_ to get all jailkit logging. If you do see jk_chrootsh logging but you don't see jk_lsh logging you probably didn't enable logging inside the jail. Read the section on logging, or read the jk_socketd manual.