Trying to setup a SFTP user with limited access.

Posted March 7, 2017 104.3k views
Linux BasicsGetting StartedSecurityUbuntu 16.04

What I want to do

I want to add a second user, but restrict what the user can do:

  • Only access a single folder called newsletters, it will be in the public folder.
  • The user needs to be able to upload, delete and rename files via SFTP
  • The user must not be able to navigate away from the newsletters, folder

This is the full path to the newsletters folder:

What I’ve done so far

I’ve followed this guide How do I restrict a user to a specific directory? by Maxamilian Demian (@Maxoplata), there’s a great reply by Jonathan Tittle (@jtittle).

However, I’m still having problems logging in via SFTP

I’ve listed out all the steps I’ve done - hopefully someone with more experience will be able to spot my error(s)!

1. Created a new user

  1. Logged in as root
  2. Created a new user called user-sftp-only
    1. adduser user-sftp-only
  3. I can check the user has been created by running
    1. compgen -u
    2. user-sftp-only is at the bottom of the list
  4. I can also see what the path of the user is and shell access by running:
  5. grep user-sftp-only /etc/passwd outputs:

2. Give new user root privileges

  1. Give new user user-sftp-only root privileges
    1. gpasswd -a user-sftp-only sudo
  2. Logout as root

3. Create a new directory

  1. Logged in as user-sftp-only
  2. Create a new directory in public called newsletters:
    1. cd /srv/users/serverpilot/apps/test-app/public/
    2. Followed by:
    3. sudo mkdir newsletters

4. Check directory permissions

  1. Still inside the public folder from the previous step, I run ls -al
  2. Shows me this:
drwxr-xr-x+ 3 serverpilot serverpilot 4096 Mar  7 15:26 .
drwxr-xr-x+ 3 serverpilot serverpilot 4096 Mar  3 16:22 ..
-rw-r--r--+ 1 serverpilot serverpilot 3393 Mar  3 16:22 index.php
drwxrwxr-x+ 2 root        root        4096 Mar  7 15:26 newsletters

From reading various DigitalOcean posts, I know I need to create a group and assign my new user user-sftp-only to that group, Then change root root to the name of my user and group.

5. Create a new group

  1. Logged in as user-sftp-only
  2. sudo groupadd group-sftp-only
  3. I can check the group has been created by running
    1. compgen -g
    2. group-sftp-only is at the bottom of the list

Note: I notice my new user called user-sftp-only is also in this list?

6. Add user to the group

  1. Logged in as root
  2. Added the user user-sftp-only to a group called group-sftp-only
  3. Doing this means it’s no longer possible to SSH in as user user-sftp-only
usermod -g group-sftp-only -d /srv/users/serverpilot/apps/test-app/public/newsletters -s /sbin/nologin user-sftp-only
  • -gspecifies the group name
  • -d specifies the users home directory
  • -s specifies shell access (/sbin/nologin means SSH is disabled for this user)

7. Verify the changes to the user

  1. Logged in as root
  2. grep user-sftp-only /etc/passwd
  3. Shows me:

8. Modify SSH Configuration to allow SFTP

  1. Logged in as root
  2. nano /etc/ssh/sshd_config
  3. Commented out this line:
  4. #Subsystem sftp /usr/lib/openssh/sftp-server -l INFO
  5. At the very bottom of sshd_config added this:
Subsystem sftp internal-sftp
    Match group group-sftp-only
    ChrootDirectory %h
    ForceCommand internal-sftp

9. Restart SSH

  1. Still logged in as root
  2. service ssh restart

10. Modify permissions

  1. Still logged in as root
  2. This is the home directory for user user-sftp-only
  3. /srv/users/serverpilot/apps/test-app/public/newsletters
  4. Used this to make sure the home directory is owned by the user and group
chown -R user-sftp-only:group-sftp-only /srv/users/serverpilot/apps/test-app/public/newsletters

11. Verify ownership change

  1. Still logged in as root
  2. cd /srv/users/serverpilot/apps/test-app/public/
  3. ls -al shows me:
drwxr-xr-x+ 3 serverpilot    serverpilot     4096 Mar  7 15:26 .
drwxr-xr-x+ 3 serverpilot    serverpilot     4096 Mar  3 16:22 ..
-rw-r--r--+ 1 serverpilot    serverpilot     3393 Mar  3 16:22 index.php
drwxrwxr-x+ 2 user-sftp-only group-sftp-only 4096 Mar  7 15:26 newsletters
  1. cd /srv/users/serverpilot/apps/test-app/public/newsletters
  2. ls -al shows me:
drwxrwxr-x+ 2 user-sftp-only group-sftp-only 4096 Mar  7 15:26 .
drwxr-xr-x+ 3 serverpilot    serverpilot     4096 Mar  7 15:26 ..

That’s where I’m up to. However, I can’t login in as my new user user-sftp-only via SFTP

Not sure where I’m going wrong - I’m new to this!


I can login via SFTP with another user name - Using a FTP client called Transmit.

If I get info on the folder newsletters everything matches what Terminal is telling me…

Here’s a screenshot

Perch Screenshot

1 comment
  • @smeehan
    What’s the error log, when you try to login? Both the log from the server /var/log/auth.log and the client.
    From what I can read in the guide, the parent folder of newsletters need to be root:root, but it’s serverpilot:serverpilot
    And I no idea why you’re giving the new user root privileges with sudo - why?
    @jtittle Can you assist, since you wrote the original guide?

These answers are provided by our Community. If you find them useful, show some love by clicking the heart. If you run into issues leave a comment, or add your own answer to help others.

Submit an Answer
5 answers

Hi @jtittle

Thank you so much for taking the time to read and reply to my post!

After following your great instructions, the user user-sftp-only is restricted to just the newsletters folder. user-sftp-only can upload, rename and delete files and sub-folders via SFTP only. Great.

If I cd to /home/user-sftp-only and run ls -l I see this:

drwxr-xr-x 2 user-sftp-only user-sftp-only 4096 Mar 8 11:58 newsletters

Next step is to configure a way to sync the files located here:


So they automatically appear here:


I found a DigitalOcean article How To Mirror Local and Remote Directories on a VPS with lsyncd. Is this what you have in mind for syncing?

by Justin Ellingwood
While administrating web and application servers, there are many times when it is useful to mirror directories. The lsyncd service can mirror local and remote directories in order to propagate changes from one location to another. This guide will cover the basic usage of this tool.
  • @smeehan

    Awesome! That’s what I needed to hear :-).

    You can use either rsync or lsyncd – they’ll both work, though lsyncd gives you a little more flexibility, but that comes with a little more complex setup (but not overly complex).

    What you’d start by doing is running the following to install lsyncd:

    sudo apt-get install lsyncd

    Then create the lsyncd base/log directory and the log/status files. This is beneficial for when/if we run in to any issues – errors will be logged, etc.

    sudo mkdir /etc/lsyncd \
    && sudo mkdir /var/log/lsyncd \
    && touch /var/log/lsyncd/lsyncd.{log,status}

    Create the configuration file:

    sudo nano /etc/lsyncd/lsyncd.conf.lua

    … and within it paste (already setup for your configuration per your provided info):

    settings = {
            logfile = "/var/log/lsyncd/lsyncd.log",
            statusFile = "/var/log/lsyncd/lsyncd.status"
    sync {
            source = "/home/user-sftp-only/newsletters",
            target = "/srv/users/serverpilot/apps/test-app/public/newsletters"

    Now start lsyncd:

    sudo service lsyncd start

    I actually had to issue:

    sudo service lsyncd restart

    … afterwards as the start didn’t seem to kick things off as it should have, so if you run in to the same issue, that should resolve it.

    Now if you cd to /home/user-sftp-only/newsletters and run:

    touch file{1..100}

    It’ll create 100 empty files in ./newsletters which, within in a few seconds, should sync to:


    Likewise, if we run:

    rm -rf /home/user-sftp-only/newsletters/*

    … within a few seconds, the files will be deleted from both as well.

    You can add delete = false to the configuration above if you would prefer that the user not be able to delete files. Essentially if they delete a file in their ./newsletters, then it won’t sync with the main directory.

    One thing to be cautious of in this case would be if they upload a file name that is the same as one you don’t want deleted, it will overwrite it, so there is one way they could get around that.

    The configuration in that case would look like:

    settings = {
            logfile = "/var/log/lsyncd/lsyncd.log",
            statusFile = "/var/log/lsyncd/lsyncd.status"
    sync {
            source = "/home/user-sftp-only/newsletters",
            target = "/srv/users/serverpilot/apps/test-app/public/newsletters",
            delete = false


Thanks for the mention! It seems the community requires a space after @ mentions, so I didn’t get tagged in this one, but glad I caught it :-). I’ll do my best to help!

When it comes to SFTP, the users home directory needs to be owned root. The user would then be able to access any/all directories below that, so that’s most likely where the issue is.

For example, if we create user-sftp-only using:

useradd -d /home/user-sftp-only user-sftp-only

The create a series of directories for that user, which they’ll be able to access once logged in:

mkdir -p /home/user-sftp-only/{public,private,logs}

And then chown those directories to the user:

chown -R user-sftp-only:user-sftp-only /home/user-sftp-only/*

The user-sftp-only user should be able to login and automatically get chrooted to / which would be /home/user-sftp-only (for them).

They should be able to access only public, private, logs (they could even delete them if they wanted, or upload files to them).

That being said, you have a unique need. You’re wanting the user-sftp-only user to be able to only access a directory that is located in a non-root owned directory, which is why you’re not able to login.

The home directory needs to be owned by root, otherwise they may be able to escape from it.

So in your case, that user should only be able to access newsletters but the following directory is not owned by root, nor should it be since it’s a public-facing directory:


So how do we work around this? If that user only needs access to that one directory, you could use either a symlink (not the best solution) or perhaps even rsync to synchronize the two directories (probably the better option so you’re not messing around with symlinks).

I would so is start fresh.

Add The User

This sets the home directory and removes the ability to login using SSH (but will allow SFTP).

useradd useradd -d /home/user-sftp-only -s /bin/nologin user-sftp-only

Add The SFTP Group

groupadd group-sftp-only

Modify The User and Append The New Group

What we’re doing here is appending the new group on to the user, so we’re not changing the current group, rather, making them a member of both their base user-sftp-only group as well as that of the newly added group-sftp-only group.

usermod -aG group-sftp-only user-sftp-only

Modify /etc/ssh/sshd_config


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


Subsystem sftp internal-sftp

And below:

UsePAM yes


Match Group group-sftp-only
   ChrootDirectory %h #set the home directory
   ForceCommand internal-sftp
   X11Forwarding no
   AllowTCPForwarding no
   PasswordAuthentication yes

Now restart SSH - service ssh restart.

Add Newsletters Directory

mkdir -p /home/user-sftp-only/newsletters

Change Ownership

You’ll note I’m using user-sftp-only for both the user and group. That’s because we didn’t change the users group when we used groupadd – we appended that group on – so we don’t need to set group-sftp-only as the group that owns the directory.

chown -R user-sftp-only:user-sftp-only /home/user-sftp-only/*

Set Password for user-sftp-only

passwd user-sftp-only

At this point, you should be able to login via SFTP and get chrooted to / which would be:


and within it should be:


If you can test to make sure that works, that’s at least step one complete and we know the user can in fact login as required. From there, it’s a matter of setting up rsync or some sort of method to make sure when files are uploaded/deleted to/from /home/user-sftp-only/newsletters, that they also do the same in the other directory.

I just pressed mark as accepted and my previous reply was removed/deleted?!

Just in case you don’t receive a email/notification with my previous reply, I’d just like to say thank you very much for your help!

hi guys,
tks for guide!
I get error in filezilla if I log with new user:
network error: software caused connection abort filezilla

Hi @jtittle

That works great! Thank you so much for your help with this.

It’s a shame deleted files aren’t also synced, but that’s ok. I’ll set delete = false If the end user ever needs to delete any files I can do it manually for them.

I’ve been struggling with this for longer than I’d like to admit! However, thanks to you and the many DigitalOcean posts I’ve read, I have expanded my knowledge of Terminal and navigating around my server.

Great stuff.

  • @smeehan

    No problem, though to clarify, deleted files are synced by default. So if a user deletes a file, it will be removed from both directories.

    The delete = false option prevents a user-deleted file from source from also being deleted from the target. It doesn’t stop, however, a user from uploading a new file of the same name and simply overwriting the existing.

    So if the user uploads newsletter01.html and you have delete = false set, they can delete that file and it won’t be removed from the target.

    If they, however, upload a new newsletter01.html file, it will overwrite the existing. I don’t see a way to prevent that right off.

    • Ah yes, I understand.

      I’ve been testing it out since my last post and found out deleted files sync too. Which is actually preferable.

      Thank you!