SFTP chroot

From ArchWiki
Revision as of 10:53, 2 August 2017 by Francoism (talk | contribs) (Installation: Added alternatives)
Jump to navigation Jump to search

OpenSSH 4.9+ includes a built-in chroot for sftp, but requires a few tweaks to the normal install.


Install and configure OpenSSH. Once running, SFTP is available by default.

Access files with the sftp program or SSHFS. Many standard FTP clients should work as well.


Secure copy protocol (SCP)

Install, configure and start openssh. It contains a scp command to transfer files. See Secure Shell for more information.

More features are available by installing additional packages, for example rsshAUR or scponly described below.


Scponly is a limited shell for allowing users scp/sftp access and only scp/sftp access. Additionally, one can setup scponly to chroot the user into a particular directory increasing the level of security.

install scponly.

For existing users, simply set the user's shell to scponly:

# usermod -s /usr/bin/scponly username
Adding a chroot jail

The package comes with a script to create a chroot. To use it, run:

# /usr/share/doc/scponly/setup_chroot.sh
  • Provide answers
  • Check that /path/to/chroot has root:root owner and r-x for others
  • Change the shell for selected user to /usr/bin/scponlyc
  • sftp-server may require some libnss modules such as libnss_files. Copy them to chroot's /lib path.


Setup the filesystem

Create a jail directory:

# mkdir -p /var/lib/jail

Bind mount the live filesystem to be shared to this directory. In this example, /mnt/data/share is to be used, owned by user root and has octal permissions of 755:

# mount -o bind /mnt/data/share /var/lib/jail
# chown root:root /mnt/data/share
# chmod 755 /mnt/data/share
  • Add entries to fstab to make the bind mount survive on a reboot.
  • Readers may select a file access scheme on their own. For example, optionally create a subdirectory for an incoming (writable) space and/or a read-only space. This need not be done directly under /var/lib/jail - it can be accomplished on the live partition which will be mounted via a bind mount as well.

Create an unprivileged user

Note: You don't need to create a group, it is possible to Match User instead of Match Group.

First, we need to create the sftponly group:

# groupadd sftponly 

Create a user:

# useradd -g sftponly -d /var/lib/jail username

To deny SSH shell access, run the following command:

# usermod username -s /bin/false

Configure OpenSSH

Note: Use Match User instead of Match Group when not using the given group.
Match Group sftponly
  ChrootDirectory %h
  ForceCommand internal-sftp
  AllowTcpForwarding no
  X11Forwarding no
  PasswordAuthentication no

Restart sshd.service to confirm the changes.

Fixing path for authorized_keys

With the standard path of AuthorizedKeysFile, the SSH keys authentication will fail for chrooted-users. To fix this, append AuthorizedKeysFile to /etc/openssh/sshd_config on a root-owned directory, e.g. /etc/ssh/authorized_keys.

AuthorizedKeysFile /etc/ssh/authorized_keys .ssh/authorized_keys

Create authorized_keys file, generate a SSH-key on the client, copy the contents of the key to /etc/ssh/authorized_keys of the server and setup permissions:

# touch /etc/ssh/authorized_keys
# echo 'ssh-rsa <key> <username@host>' >> /etc/ssh/authorized_keys

Restart sshd.service.

Tips and tricks


The user will not be able to access /dev/log. This can be seen by running strace on the process once the user connects and attempts to download a file.

Create sub directory

Create the sub-directory dev in the ChrootDirectory, for example:

# mkdir /usr/local/chroot/user/dev
# chmod 755 /usr/local/chroot/user/dev

syslog-ng will create the device /usr/local/chroot/theuser/dev/log once configured.

Syslog-ng configuration

Add to /etc/syslog-ng/syslog-ng.conf a new source for the log and add the configuration, for example change the section:

source src {


source src {

and append:

#sftp configuration
destination sftp { file("/var/log/sftp.log"); };
filter f_sftp { program("internal-sftp"); };
log { source(src); filter(f_sftp); destination(sftp); };

(Optional) If you'd like to similarly log SSH messages to it's own file:

#sshd configuration
destination ssh { file("/var/log/ssh.log"); };
filter f_ssh { program("sshd"); };
log { source(src); filter(f_ssh); destination(ssh); };

(From Syslog-ng#Move log to another file)

OpenSSH configuration

Edit /etc/ssh/sshd_config to replace all instances of internal-sftp with internal-sftp -f AUTH -l VERBOSE

Restart service

Restart service syslog-ng and sshd.

/usr/local/chroot/theuser/dev/log should now exist.

See also