Configuring SFTP for the document root

How to configure SFTP for a web server document root

Last updated on

SFTP is the favourite these days because of its robust security model and easier setup than traditional FTP and FTPS. In this guide we will configure SFTP to allow users to upload to the web server document root.

Introduction

In this guide we will assume these two scenarios:

  • The SFTP user should only have access to the web document root.
  • The SFTP user should not be able to log in to terminal over SSH.

If you only intend on accessing the document root using one SFTP user, continue to Step 1 below.

If you intend on having multiple SFTP users uploading to the document root, such as in a multi-developer environment, skip to Step 2 further down the page.

1. Set up SFTP for one user

Setting up SFTP for one user is straightforward enough with only a small amount of configuration involved.

1.1 Add user

It’s not recommended that you use the root account or any account with sudo privileges to upload files to the web server document root. For that reason, we will create a new user called webdev – you can call this whatever you want.

sudo adduser webdev

Generate and password and press enter to accept all defaults.

1.2 Test SFTP

You can now log in using this user in your FTP client. In this example we are using FileZilla.

Enter the server host, select the SFTP protocol and enter user and password, then click Connect.

Once logged in, you will see we are brought to the home folder for the user webdev.

There are two issues here. The first is that we want it to go to the document root, not the user’s home folder. The other problem is that users can browse outside their home folder and view the entire server!

1.3 Restrict user to the document root

We will now restrict the user webdev to the document root and also disable their SSH access – we only want them to be able to log in over SFTP.

Begin by opening sshd_config

sudo nano /etc/ssh/sshd_config

Scroll to the bottom of the file and comment out the line Subsystem sftp by adding a # sign before it and paste in Subsystem sftp internal-sftp below it.

/etc/ssh/sshd_config
#Subsystem sftp        /usr/lib/openssh/sftp-server
Subsystem sftp internal-sftp

Below this, we will add a new Match User directive. Make sure that ChrootDirectory is the directory above your document root. For example, if your document root is /var/www/html/, then the ChrootDirectory is  /var/www/. If you followed one of our previous guides on setting up multiple domains, your document root may be located in /var/www/mydomain.com/public_html, in that case, your ChrootDirectory is /var/www/mydomain.com/

/etc/ssh/sshd_config
Match User webdev
        ChrootDirectory /var/www/
        ForceCommand internal-sftp -u 0022
        X11Forwarding no
        AllowTcpForwarding no
        PasswordAuthentication yes

Note: ForceCommand internal-sftp will prevent this user from logging in over SSH, which is what we want. Never add your root account or any account you use to administer the Linux server to this because you may get locked out of SSH permanently!

-u 0022 will set the default permissions for folders created over SFTP to 755 (the default is 775 and only necessary if using groups).

Save changes and close nano (Press CTRL + X and then press y and ENTER)

Restart the sshd service.

sudo service sshd restart

The user root must own the directory above the document root otherwise SFTP will refuse the connection. This should match your ChrootDirectory above, so it’s either /var/www/ or /var/www/mydomain.com/ – be sure to get it right!

sudo chown root:root /var/www/

Now, let’s log in again and try to write to the document root.

SFTP FilZilla - Can't write to document root.

To solve this, we need to set up some additional permissions on the document root.

1.4 Directory Permissions

Let’s first check the current permissions for the document root. Your document root is either /var/www/html/ or /var/www/mydomain.com/public_html – get it right!

ls -ld /var/www/html

Below we can see that root owns the document root, this is why out user webdev can’t write to it.

drwxr-xr-x 2 root root 4096 Jun 19 12:17 /var/www/html

Let’s change the owner to webdev. -R and *  below instruct Linux to run recursively through every file and folder in the document root. Your document root is either /var/www/html/ or /var/www/mydomain.com/public_html – get it right!

sudo chown -R webdev:webdev /var/www/html*

Now check permissions again

ls -ld /var/www/html

Below we can see that webdev now owns the document root.

drwxr-xr-x 2 webdev webdev 4096 Jun 19 12:17 /var/www/html

Log in again and try to create a folder to ensure permissions are working correctly.

FileZilla - I can write to document root now

You’re all set.

If you would like to add additional SFTP users, for example, in a multi-developer environment, read on to Step 2, otherwise, goodbye!

2. SFTP for Multiple Users

Setting up SFTP for multiple users involves a little more configuration, but the security benefits are well worth it.

2.1 Test SFTP

Before you do any configuration, you should first confirm that SFTP is indeed working. Log in using your root or personal account.

In this example we are using FileZilla. Enter the server host, select the SFTP protocol and enter user and password, then click Connect.

If SFTP is working, you can now continue setting up groups.

2.2 Create Group

For optimal security and convenience, we use groups to group together all users who have access to the document root. For example, you may have multiple web developers working on the document root and want to audit their activity. Groups also allow us to easily add new SFTP users in future without having to configure permissions for each separate user. We will also be restricting where the Apache or Nginx service group www-data can write to for added security.

For users that need SFTP access to the web document root, we will add them to a special group called docrootonly. You can call this whatever you like. This group is chrooted to the web document root using /etc/ssh/sshd_config so that users can’t browse above the document root. Chroot in Linux allows us to “jail” users to a particular directory.

Let’s begin by creating a new group:

sudo groupadd docrootonly

2.3 Add new SFTP user

It’s not recommended that you use the root account or any account with sudo privileges to upload files to the web server document root. For that reason, you should create your SFTP users separately with restricted accounts.

You can add as many new users as you wish here. In this example, we will create one new user called webdev

sudo adduser webdev

Generate and password and press enter to accept all defaults.

Add this user webdev to the group docrootonly.

sudo usermod -a -G docrootonly webdev

2.4 Group Restrictions

We will now restrict all users in this group to the document root and also disable their SSH access – we only want them to be able to log in over SFTP.

Restrict this new group to the document root by editing sshd_config

sudo nano /etc/ssh/sshd_config

Scroll to the bottom of the file and comment out the line Subsystem sftp by adding a # sign before it and paste in Subsystem sftp internal-sftp

/etc/ssh/sshd_config
#Subsystem sftp        /usr/lib/openssh/sftp-server
Subsystem sftp internal-sftp

Below this, we will add a new Match Group .

Make sure that ChrootDirectory is the directory above your document root. For example, if your document root is /var/www/html/, then the ChrootDirectory is  /var/www/. If you followed one of our previous guides on setting up multiple domains, your document root may be located in /var/www/mydomain.com/public_html, in that case, your ChrootDirectory is /var/www/mydomain.com/

/etc/ssh/sshd_config
Match Group docrootonly
        ChrootDirectory /var/www/
        ForceCommand internal-sftp
        X11Forwarding no
        AllowTcpForwarding no
        PasswordAuthentication yes

Note: ForceCommand internal-sftp will prevent users in this group from logging in over SSH, which is what we want. Never add your root account or any account you use to administer the Linux server to the docrootonly group because you may get locked out of SSH permanently!

Save changes and close nano (Press CTRL + X and then press y and ENTER)

Restart the sshd service.

sudo service sshd restart

2.5 Set Directory Permissions

chown allows us to change the owner of files and folders in Linux.

The user root must own the directory above the document root otherwise SFTP will refuse the connection. This should match your ChrootDirectory above, so it’s either /var/www/ or /var/www/mydomain.com/ – be sure to get it right!

sudo chown root:root /var/www/

The user root and the group docrootonly must own the document root in order to write to it (and any files and folders you may already have in it).

Your document root is either /var/www/html/ or /var/www/mydomain.com/public_html – get it right!

-R and *  instruct Linux to run recursively through every file and folder in the document root.

sudo chown -R root:docrootonly /var/www/html*

To allow groups write access to our document root, the document root and all its subfolders must be set the 775. Again, your document root is either /var/www/html/ or /var/www/mydomain.com/public_html . The command below will set the document root and all subfolders to 775.

sudo find /var/www/html/ -type d -exec chmod g+s {} \;

Lastly, we want any new files/folders created in the document root from now on to inherit the group name.

sudo chmod g+s /var/www/html/

Phew! You’re done. You should test log in to SFTP and ensure you can write files and folders.

Let me know in the comments if this helped. Follow me @DevAnswers or read more.

1 Star2 Stars3 Stars4 Stars5 Stars 5.00 (3 votes)

Feedback

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

We use Markdown to style comments, like on Github and Reddit.
To do a line break, type two spaces after the sentence.
You can add inline code by wrapping it in backticks: `code here`

    To do an entire block of code  
    type four spaces before the line
    and it will appear in a block like this.
    <-- four empty spaces

7 replies

Something I don’t understand about your instructions, and I’m a learner so I don’t want to say YOU’VE GOT IT WRONG when it is much more likely that I’m misunderstanding something, so please correct me!
(By the way, having to exclude code from my feedback because with code, getting blocked by cloudflare)

But, as I understand it
SFTP protocol explicitly depends on the user having SSH. To be denied an SSH login is to be denied an SFTP login.

So Step 1.3 is to “(…) restrict the user (…) to the document root and also disable their SSH access – we only want them to be able to log in over SFTP.” and that contradicts what I understand about SFTP.

Experience bears this out; If I include the line (code broken up to allow without cloudflare having a hissy fit) Fo rc eC om ma nd inte rn al-sf tp in my file /e tc/ss h/s shd _con fig , I can’t log in with FileZilla. If I comment it out and reload sshd then filezilla works over sftp.

I first followed this to try a single user with access to an experimental directory. It worked fine. Then I wanted to try adding a user to a group, and setting up the group access like you described in part 2. I was able to get the user to log in and navigate all through the folders down from the chroot, but I get a permissions denied message when trying to upload files to any of the directories.

So you should check the permissions for the directory and make sure they are set to the correct group. e.g:

ls -ld /var/www/html

I followed this tut yesterday, and everything was working fine, except none of the users I created had access to upload anything to the server.

So after reading more about permissions and groups, I changed some permissions settings. Restarted the server, and now I can’t connect at all. Running FileZilla on the server computer, gives the error:
Error: Connection reset by peer
Error: Could not connect to server

From any of my other computers, I get:
Network Error: Software caused connection to abort.

Any ideas, what happened, an/or how to fix it?

Are you able to SFTP in using your root or sysadmin account?

I decided to double check the newest parts I added to the sshd config, and compared it to items listed in this tutorial, and discovered I had a couple errors. Basically, the chroot was wrong for my sites. I had it set for var www mydomain.com public_html. Once I removed the public_html, from the end of each entry, I was able to log in again, and upload files.

However, in the process, I discovered one of my sites is not functioning at all. And giving a error 500: This page isn’t working
masterbuddasartgallery.com is currently unable to handle this request.
HTTP ERROR 500.

I’m thinking it’s due to the old server it was hosted on was using Apache. and I’m now using Nginx. So looking into how to transfer it over. Already set the database up for it, so that part “should” work. LOL