I am an active member in quite a few linux online communities and I see this question asked repeatedly by users new to SFTP. First let’s start off with a short explanation of what SFTP is, and how it is different from FTPS.

SFTP vs FTPS

FTP was a widely popular protocol used to transfer files from one system to another, but it had one major flaw. It would transmit usernames and passwords in plain text. This made it quite easy for someone listening on the wire to extract this information and use those credentials for their own, usually malicious, reasons.

FTPS is an extension of the basic FTP protocol that has added support for encryption using SSL. This added a layer of security on top of the already popular FTP protocol.

SFTP is a subsystem of the SSH (Secure Shell) protocol. It does not use FTP, nor does it require FTP software for the SFTP server to function. I mention this because I see a lot of people ask questions like “How can I configure SFTP with VSFTPD”? The short answer is "You cannot".

Implementation of SFTP

In order to use SFTP you must have OpenSSH version 4.8 or newer installed. To find out what version of SSH you currently have installed on your system use the following command:

ssh -V

Example output:

# ssh -V
OpenSSH_5.5p1, OpenSSL 1.0.0d-fips 8 Feb 2011

We will not cover how to install OpenSSH as that is beyond the scope of this tutorial. More information can be found at the OpenSSH homepage.

Configuring chroot environment

The default SSH configuration drops users into their home directory by default. With a few basic commands (cd /) they can back out of their home directory and into the root directory. To stop this and confine a user to their home directory we chroot the user. The act of locking or confining a user to a certain directory is called chroot or chrooting, which means “change root directory”. Chrooting a user will for all intents and purposes change their root directory to their home directory. They will not be able to back out of the directory.

Configure SSH Daemon

To begin we will need to edit the /etc/ssh/sshd_config (or /etc/sshd_config depending on your distribution and set the following options:

Subsystem sftp internal-sftp
Match Group sftp
ChrootDirectory %h
ForceCommand internal-sftp
AllowTcpForwarding no

Make sure you add the match directive at the end of the file. This tells the SSH daemon to confine users in the sftp group to %h (which is the home directory of the user).

Add Necessary Users & Groups

Now let’s create the sftp group, create a user, create a password for that user and add them to the sftp group.

# groupadd sftp
# useradd johndoe
# passwd johndoe
# usermod -G sftp johndoe

Now we have a new user johndoe, and he is a member of the sftp group.

# id johndoe
uid=502(johndoe) gid=502(johndoe) groups=502(johndoe),503(sftp)

Restrict Shell Access

Let’s take away the users shell access so he/she can ONLY access the server via SFTP and never have shell access.

# usermod -s /bin/false johndoe

One last thing to complete in order to successfully lock the user into their home directory. We need to change the owner of their home directory to root, and set permissions.

# chown root:root /home/johndoe
# chmod 0755 /home/johndoe

Set User Read/Write Folder

The above directory modifications are required for a secure chroot. But this limits what a user can do, for example with the current setup the user will be able to log in, but not be able to create a directory or upload any files. So let's create a new directory inside owned by the user inside of the home directory.

# mkdir /home/johndoe/html
# chown johndoe /home/johndoe/html/

This will allow the user FULL access to html directory to upload, download and create additional directories, but limit access to his home directory (now effectively his ROOT directory). You can now put links to other resources you would like him to have read access to in his home directory.

Troubleshooting

NOTES: If your running RedHat or any other OS with selinux (ex. Centos, Fedora) you may run into problems with access for selinux. If you are getting results other than what you expect I would look at selinux first. You can test by setting selinux into permissive mode where it will ALLOW the action but still report it. You can do this by entering the following command as root:

# setenforce 0

Kevin G wrote in to say that he fixed his issue with selinux with the following command:

# grep sshd /var/log/audit/audit.log | audit2allow -M mypol; semodule -i mypol.pp