Setting Up vsftpd on CentOS with a Perfect CHROOT

SFTP servers are very popular and there are a multitude of guides to out there on how to set them up. I found however that typically with the basic configuration users will still be able to access parent directories  and see the files contained within due to the required permissions on a user’s home drive. For example, if you were to install vsftpd using the guide found here, you would be able to browse to the root:

2016-08-28 18_13_16-Users - - WinSCP

The solution was to create a new directory structure with specific permissions that will emulate the structure of the home directory. To the end user it will look like they’re home directory but it will actually be in an alternate location. This is best used for a pure SFTP server where users will only ever connect using SFTP to upload and download files.

This will assume that the server has basic configuration with networking, and SSH is installed/enabled.

Setting Up the Server

The first thing to do is install the SFTP server itself

yum install vsftpd -y

Once it’s installed we can configure vsftpd, so open up /etc/vsftpd/vsftpd.conf and and make sure the settings below are configured. If need be uncomment or add in the entries.


We’ll also need to configure which sftp server is used, so open up /etc/ssh/sshd_config and make the changes below.

#Subsystem    sftp    /usr/libexec/openssh/sftp
Subsystem     sftp    internal-sftp

To make these configuration changes take effect we’ll restart both services

systemctl restart vsftpd
systemctl restart sshd

Now we’ll create our directory structure which will contain our users’ chroot directories

mkdir /usr/sftp/
chown root:root /usr
chown root:root /usr/sftp

Make sure that the vsftpd service starts at boot

systemctl enable vsftpd

You may also need to open up the firewall. For iptables use:

iptables –A INPUT –p tcp –dport ssh –j ACCEPT
iptables -A OUTPUT –p tcp –dport ssh –j ACCEPT

Or for firewalld

firewall-cmd --zone=public --add-service=ssh
firewall-cmd --reload

Creating Users

Now that the server is setup you can create users. To do so, first create the user and give it a password

useradd <username>
passwd <username>

Once you run passwd it will prompt for the password to give the user, enter something secure.

We’ll disallow the user from signing in, this will not allow them to actually access a shell, they will only be able to connect for SFTP. This is done by setting their shell to /sbin/nlogon. You can find more about how that works here:

usermod –s /sbin/nologin <username>

Create a directory for the user underneath /usr/sftp. This should be in the structure <username>/home/<username>. For example /usr/sftp/thomas/home/thomas.

mkdir -p /usr/sftp/<username>/home/<username>

The next thing to do is lock down access to the directory structure, this will make it so the user will not be able to see anything outside their “home” directory.

chmod 755 /usr/sftp/<username>
chmod 755 /usr/sftp/<username>/home
chmod 700 /usr/sftp/<username>/home/<username>
chown root:root /usr/sftp/<username>
chown root:root /usr/sftp/<username>/home
chown <username>:<username> /usr/sftp/<username>/home/<username>

Now that the directory has been created and permissions assigned we’ll specify this as the chroot directory in the SSH configuration. Open up /etc/ssh/sshd_config and then at the bottom add in:

Match User <username>
ChrootDirectory /usr/sftp/<username>
ForceCommand internal-sftp

Lastly, restart SSH.

systemctl restart sshd

At this point you should be able to connect to your SFTP server and you’ll only be able to see your own directory!

2016-08-28 18_20_41-Users - - WinSCP

Scripting It

Of course, a repetitive process like this could be improved by creating a script. This will make it easier to set up users and reduce the possibility of mistakes. Here’s the script:


if [ $# -eq 0 ]
        echo "Error: Please enter a username to add to the SFTP server"


for var in "$@"
        id -u "$var" > /dev/null 2>&1 && ret=true
        if [ $? -eq "1" ]
                echo "Error: User $var already exists"
        elif [[ ! $var =~ $validUsernameRegex ]]
                echo "Error: $var is an invalid username"
                useradd $var
                passwd $var
                usermod -s /sbin/nologin $var
                mkdir -p $userDir
                chown $var:$var $userDir
                chmod 700 $userDir
                echo >> /etc/ssh/sshd_config
                echo "Match User $var" >> /etc/ssh/sshd_config
                echo "ChrootDirectory /usr/sftp/$var" >> /etc/ssh/sshd_config
                echo "ForceCommand internal-sftp" >> /etc/ssh/sshd_config                
        echo "User $var successfully created"

systemctl restart sshd.service

This will allow you to enter as many users as you like and it will create a user for each. It will prompt you for a password for each user as it runs through the script.

Leave a Reply

Your email address will not be published. Required fields are marked *