Securing SFTP with Chroot Jails

-7 min read

When you provide SFTP access to external users or clients, one of the most critical security measures is preventing them from navigating outside their designated directory. This is where chroot jails come in.

Diagram comparing a filesystem without chroot where users can access system directories versus a chroot jail where users are confined to their own directory

What is a Chroot Jail?

A chroot ("change root") jail changes the apparent root directory for a running process. When applied to an SFTP session, the user sees their home directory as the filesystem root (/). They cannot navigate above it, access system files like /etc/passwd, or see other users' directories.

How OpenSSH Implements Chroot

OpenSSH's ChrootDirectory directive in sshd_config enforces the jail. When configured, the SFTP subsystem changes the root directory before granting the user access.

Requirements for Chroot

  • The chroot directory must be owned by root
  • The chroot directory must not be writable by any other user or group
  • A writable subdirectory (e.g., /files) inside the chroot is needed for the user to actually upload files
  • The user's shell must be set to /usr/sbin/nologin or /bin/false

Typical Directory Structure

/home/sftpuser/          # owned by root:root, 755
  /home/sftpuser/files/  # owned by sftpuser:sftpuser, 755

Setting Up a Chrooted User

The typical steps to configure a chrooted SFTP user are:

  1. Create the system user with /usr/sbin/nologin as the shell
  2. Set the home directory ownership to root with correct permissions (755)
  3. Create a writable subdirectory (e.g., /files) owned by the SFTP user
  4. Add the user to a dedicated group (e.g., sftpusers)
  5. Add a Match Group or Match User block in sshd_config with ChrootDirectory
  6. Restart the SSH service for changes to take effect

Automating these steps through scripts or management tools reduces the risk of misconfiguration and ensures consistent setup across all users.

Common Chroot Pitfalls

  • Wrong ownership: If the chroot directory is not owned by root, SSH will reject the connection with a cryptic error.
  • Writable chroot root: The chroot directory itself must not be writable by the user. Only subdirectories should be writable.
  • Missing sshd restart: After modifying sshd_config, you must restart the SSH service for changes to take effect.
  • Incorrect Match block: sshd_config Match blocks must be at the end of the file and properly scoped.

Testing Your Chroot Setup

After creating a chrooted user, test the jail:

sftp username@yourserver.com
sftp> pwd
Remote working directory: /
sftp> ls
files
sftp> cd /etc
Couldn't stat remote file: No such file or directory

The user sees / as their root and cannot access system directories.