SFTP isn’t really a protocol on its own; it’s just SSH with a file-transfer subsystem tacked on.

Let’s get an SFTP server up and running. We’ll use sshd itself, which is already installed on most Linux systems.

First, ensure you have openssh-server installed:

sudo apt update && sudo apt install openssh-server

Or on RHEL/CentOS:

sudo yum update && sudo yum install openssh-server

Now, we need to configure sshd to allow SFTP. The default sshd_config (/etc/ssh/sshd_config) usually has this set up, but we’ll explicitly check and potentially modify it.

The key directive is Subsystem sftp. It tells SSH which program to execute when a client requests the SFTP subsystem. The standard setup is:

Subsystem sftp /usr/lib/openssh/sftp-server

If this line is commented out (starts with #) or missing, uncomment or add it. The path to sftp-server might vary slightly depending on your distribution. You can find it using which sftp-server or find /usr/ -name sftp-server.

After modifying sshd_config, you must reload or restart the sshd service for the changes to take effect:

sudo systemctl reload sshd

or

sudo systemctl restart sshd

Now, let’s create a dedicated user for SFTP access. It’s a bad idea to use root or your regular user for this. We’ll call our user sftpuser.

sudo adduser sftpuser

This command will prompt you to set a password and some optional information.

Next, we need to configure sshd_config for chrooting this user. Chrooting restricts the user to a specific directory, preventing them from seeing or accessing anything outside of it. This is crucial for security.

We’ll use Match User to apply specific configurations only to sftpuser. Add the following block to the end of your /etc/ssh/sshd_config file:

Match User sftpuser
    ChrootDirectory /home/sftpuser
    ForceCommand internal-sftp
    AllowTcpForwarding no
    X11Forwarding no

Let’s break this down:

  • Match User sftpuser: This section only applies to the user sftpuser.
  • ChrootDirectory /home/sftpuser: This is the directory sftpuser will be confined to. The SSH daemon will chroot into this directory. Crucially, this directory and all its parent directories up to the root must be owned by root and not writable by any other user or group. This is a security requirement of sshd.
  • ForceCommand internal-sftp: This forces the user to use the internal SFTP server, preventing them from executing arbitrary shell commands.
  • AllowTcpForwarding no and X11Forwarding no: These disable features that are not needed for SFTP and reduce the attack surface.

Now, let’s set up the directory permissions for ChrootDirectory.

First, ensure the user sftpuser is created and has a password.

Then, we need to make sure /home/sftpuser is owned by root.

sudo chown root:root /home/sftpuser
sudo chmod 755 /home/sftpuser

Inside this chroot directory, you’ll want to create a directory where sftpuser can actually upload files. This subdirectory should be owned by sftpuser.

sudo mkdir /home/sftpuser/uploads
sudo chown sftpuser:sftpuser /home/sftpuser/uploads

Now, reload sshd again for the Match User block to take effect:

sudo systemctl reload sshd

You should now be able to connect as sftpuser using an SFTP client (like FileZilla, Cyberduck, or the command-line sftp client) and upload files to the /uploads directory. You will not be able to navigate outside of /home/sftpuser.

If you try to connect and get an error like "Permission denied, please login as a user with SFTP privileges" or "fatal: bad ownership or modes for chroot directory component", double-check the ownership and permissions of /home/sftpuser and its parent directories. They must be owned by root:root and have no write permissions for others.

The next thing you’ll likely want to configure is setting up SSH keys for passwordless SFTP authentication.

Want structured learning?

Take the full Ssh course →