How to Setup Chroot SFTP in Linux (Allow Only SFTP, not SSH)

by Ramesh Natarajan on March 28, 2012

If you want to setup an account on your system that will be used only to transfer files (and not to ssh to the system), you should setup SFTP Chroot Jail as explained in this article.

In a typical sftp scenario (when chroot sftp is not setup), if you use sftp, you can see root’s file as shown below.

If you want to give sftp access on your system to outside vendors to transfer files, you should not use standard sftp. Instead, you should setup Chroot SFTP Jail as explained below.

Non-Chroot SFTP Environment

In the following example (a typical sftp environment), john can sftp to the system, and view /etc folder and download the files from there.

# sftp
john@thegeekstuff's password:
sftp> pwd
Remote working directory: /home/john

sftp> ls
projects  john.txt documents 

sftp> cd /etc
sftp> ls -l passwd
-rw-r--r--    0 0        0            3750 Dec 29 23:09 passwd

sftp> get passwd
Fetching /etc/passwd to passwd
/etc/passwd     100% 3750     3.7KB/s   00:00

Chroot SFTP Environment

In the following example, john can sftp to the system, and view only the directory that you’ve designated for john to perform sftp (i.e /incoming).

When john tries to perform ‘cd /etc’, it will give an error message. Since SFTP is setup in an chroot environment, john cannot view any other files in the system.

# sftp
john@thegeekstuff's password:
sftp> pwd
Remote working directory: /home/john

sftp> ls
sftp> cd /etc
Couldn't canonicalise: No such file or directory

Now that you know what Chroot SFTP environment is, let us see how to set this up.

1. Create a New Group

Create a group called sftpusers. Only users who belong to this group will be automatically restricted to the SFTP chroot environment on this system.

# groupadd sftpusers

2. Create Users (or Modify Existing User)

Let us say you want to create an user guestuser who should be allowed only to perform SFTP in a chroot environment, and should not be allowed to perform SSH.

The following command creates guestuser, assigns this user to sftpusers group, make /incoming as the home directory, set /sbin/nologin as shell (which will not allow the user to ssh and get shell access).

# useradd -g sftpusers -d /incoming -s /sbin/nologin guestuser
# passwd guestuser

Verify that the user got created properly.

# grep guestuser /etc/passwd

If you want to modify an existing user and make him an sftp user only and put him in the chroot sftp jail, do the following:

# usermod -g sftpusers -d /incoming -s /sbin/nologin john

On a related note, if you have to transfer files from windows to Linux, use any one of the sftp client mentioned in this top 7 sftp client list.

3. Setup sftp-server Subsystem in sshd_config

You should instruct sshd to use the internal-sftp for sftp (instead of the default sftp-server).

Modify the the /etc/ssh/sshd_config file and comment out the following line:

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

Next, add the following line to the /etc/ssh/sshd_config file

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

4. Specify Chroot Directory for a Group

You want to put only certain users (i.e users who belongs to sftpusers group) in the chroot jail environment. Add the following lines at the end of /etc/ssh/sshd_config

# tail /etc/ssh/sshd_config
Match Group sftpusers
        ChrootDirectory /sftp/%u
        ForceCommand internal-sftp

In the above:

  • Match Group sftpusers – This indicates that the following lines will be matched only for users who belong to group sftpusers
  • ChrootDirectory /sftp/%u – This is the path that will be used for chroot after the user is authenticated. %u indicates the user. So, for john, this will be /sftp/john.
  • ForceCommand internal-sftp – This forces the execution of the internal-sftp and ignores any command that are mentioned in the ~/.ssh/rc file.

5. Create sftp Home Directory

Since we’ve specified /sftp as ChrootDirectory above, create this directory (which iw equivalent of your typical /home directory).

# mkdir /sftp

Now, under /sftp, create the individual directories for the users who are part of the sftpusers group. i.e the users who will be allowed only to perform sftp and will be in chroot environment.

# mkdir /sftp/guestuser

So, /sftp/guestuser is equivalent to / for the guestuser. When guestuser sftp to the system, and performs “cd /”, they’ll be seeing only the content of the directories under “/sftp/guestuser” (and not the real / of the system). This is the power of the chroot.

So, under this directory /sftp/guestuser, create any subdirectory that you like user to see. For example, create a incoming directory where users can sftp their files.

# mkdir /sftp/guestuser/incoming

6. Setup Appropriate Permission

For chroot to work properly, you need to make sure appropriate permissions are setup properly on the directory you just created above.

Set the owenership to the user, and group to the sftpusers group as shown below.

# chown guestuser:sftpusers /sftp/guestuser/incoming

The permission will look like the following for the incoming directory.

# ls -ld /sftp/guestuser/incoming
drwxr-xr-x 2 guestuser sftpusers 4096 Dec 28 23:49 /sftp/guestuser/incoming

The permission will look like the following for the /sftp/guestuser directory

# ls -ld /sftp/guestuser
drwxr-xr-x 3 root root 4096 Dec 28 23:49 /sftp/guestuser

# ls -ld /sftp
drwxr-xr-x 3 root root 4096 Dec 28 23:49 /sftp

7. Restart sshd and Test Chroot SFTP

Restart sshd:

# service sshd restart

Test chroot sftp environment. As you see below, when gusetuser does sftp, and does “cd /”, they’ll only see incoming directory.

# sftp
guestuser@thegeekstuff's password:

sftp> pwd
Remote working directory: /incoming

sftp> cd /
sftp> ls

When guestuser transfers any files to the /incoming directory from the sftp, they’ll be really located under /sftp/guestuser/incoming directory on the system.

If you enjoyed this article, you might also like..

  1. 50 Linux Sysadmin Tutorials
  2. 50 Most Frequently Used Linux Commands (With Examples)
  3. Top 25 Best Linux Performance Monitoring and Debugging Tools
  4. Mommy, I found it! – 15 Practical Linux Find Command Examples
  5. Linux 101 Hacks 2nd Edition eBook Linux 101 Hacks Book

Bash 101 Hacks Book Sed and Awk 101 Hacks Book Nagios Core 3 Book Vim 101 Hacks Book

{ 54 comments… read them below or add one }

1 Suresh Danda March 28, 2012 at 2:54 am


Nice post Ramesh Natarajan.

It helps for single sftp user environment … we can do like below in easy way also.

and also it works for multiple users also.

If we are using (openssh-server-4.3p2-30.el5) which is shipped in Red Hat enterprise Linux 5.4

1.Create a specific chrooted directory.
#mkdir /chroot/home
2.Mount it to /home as follows:
mount -o bind /home /chroot/home
3.Edit /etc/ssh/sshd_config as follows:
ChrootDirectory /chroot
Subsystem sftp internal-sftp
4.Save & Exit
4.service sshd restart


2 Eric March 28, 2012 at 3:18 am


Take into account that the match keyword is not supported in older versions (<5) on SSH so your solution will not work on for example RHEL 5.7 which has version 4.X installed. An upgrade of openssh will be necessary.

Kind regards,


3 pat March 28, 2012 at 3:24 am

To increase security just a little bit more: Add the rssh shell to this setup.

4 Jalal Hajigholamali March 28, 2012 at 6:10 am


Very Nice post

Thanks a lot for your nice topics….

5 Babar Singh March 28, 2012 at 6:32 am

Thanks for the post. Helped a lot

6 Luis Rojas March 28, 2012 at 8:22 am

Very nice post, just in time to help me set up precisely this kind of access at my company.

Thank you!

7 bob March 28, 2012 at 9:35 am

nice post. But what does the acronmym “chroot” stand for. If you explain that it will make it easier to recall it in a few months.

8 Chroot March 28, 2012 at 4:03 pm

chroot = change root directory, a chrooted service doesn’t ‘see’ the rest of the filesystem (well, roughly, there’s the headache of running binaries in a chrooted environment and whatnot, but that’s another story!)

9 tohid ansari June 11, 2012 at 10:16 pm

good document and easy.thank

10 Alberto June 29, 2012 at 12:44 am

Great post !!!!!

11 Itamar July 24, 2012 at 2:32 am

I am trying with server CentOS 6.2 with openssh 5.3 (Eric is right) and WinSCP client.
I have did everything exactly how it’s written here, but I am getting this error on the WinSCP client:
Error listing directory ‘incoming’
Permission denied.
Error code: 3
Error message from server: Permission denied
Request code: 11
Any ideas?

12 Soultani July 31, 2012 at 9:08 pm

Hi Itamar..

I’m facing the same problem to not so long ago.. it turn out SELinux was the culprit. I did:

# setenforce 0 (press enter)

for more details here. and it works!! hope the same goes for you…..

13 Itamar August 4, 2012 at 11:59 pm

Hi Soultani,

Thanks for the replay.

The Selinux is not the issue in my case, it is disabled.
FYI,I created a sub directory (under the user root-home) and gave the user full permissions, there the user is able to put his files. fine by me for now.

14 Preashant September 5, 2012 at 9:07 pm

Hi Soultani,

Thanks for the replay. I have spend 3 days to resolve this issue thanks for your help

15 Marcos September 12, 2012 at 9:18 am

I sucessfully followed the instructions and it worked fine. Now I need to set the sftp user to connect without password, using certificates, but it doesn’t work. Any ideas?


16 FWord3 September 26, 2012 at 12:56 pm

Make sure the following ownership and permissions are set for your chroot sFTP account (Example is based on the user information in Ramesh’s artical above). It’s important that the guestusers home is owned by root. The permissions are also important especially for the home dir, .ssh dir, and authorized_keys file.

# ls -ld ~guestuser
drwxr-x-r-x 5 root root 4096 Sep 25 17:11 /sftp/guestuser

#ls -al ~guestuser
drwxr-x-r-x 5 root root 4096 Sep 25 17:11 .
drwxr-x-r-x 5 root root 4096 Sep 25 17:11 ..
drwx——- 5 guestuser sftpusers 4096 Sep 25 17:11 .ssh
drwxr-x-r-x 5 guestuser sftpusers 126976 Sep 25 17:11 incoming

# ls -l ~ddtocai/.ssh
-rw——– 1 guestuser sftpusers 5522 Sep 25 17:11 authorized_keys

NOTE: To further troubleshoot your access issue, use the sftp command with the -v flag set to enable verbose mode of the command. This will show you all the intraction between the sftp site and the user attempting access. You can also startup another sshd daemon on your sftp site in debug mode to listen on another port without interruption to your current running sshd daemons. Do the following to accomplish this.

On the sftp device (you do not have to use port 3377, any open port will do):
# /usr/local/sbin/sshd -p 3377 -d

On the device attempting access:
# sftp -P 3377 -v guestuser@sftpdevice

The sshd daemon on port 3377 should exit after the first access attempt. If not use ctrl-c to exit.

17 Raghava September 27, 2012 at 1:02 pm

My requirement is like.. allow the user to sftp only but not SSH and want to share secure files eventually (either through hard liks/ soft links/ mount). I am fresh bee to RHEL with internal sftp, Please point me with the guidelines or solution ASAP.

18 Leticia September 30, 2012 at 4:43 pm

Thanks. Had a problem with sftp. This solved it.

19 Benoit October 17, 2012 at 9:08 pm

Thank you . Very clear and helpful.

20 James October 18, 2012 at 7:46 am


I followed the instructions but on the ssh restart i got:

Starting sshd: /etc/ssh/sshd_config: line 131: Bad configuration option: Match
/etc/ssh/sshd_config: line 132: Bad configuration option: ChrootDirectory
/etc/ssh/sshd_config: line 133: Bad configuration option: ForceCommand
/etc/ssh/sshd_config: terminating, 3 bad configuration options

Do I need to upgrade ssh as suggested?

21 FWord3 October 18, 2012 at 10:38 am

Yes you have to upgrade your ssh version to at least 5.9 if I’m not mistaken.

22 Raghava October 18, 2012 at 10:42 am

I used sshpass tool to connect to remote sshd service. its connecting to that when I run it from command line but not get connecting when I run the same command through shell script. It shown command not found. what might be the issue?


23 FWord3 October 18, 2012 at 10:48 am

Your script runs in a seperate shell from your user account. You’ll need to add the path to the sshpass app in your script.

Here is an example using tnsping. Just replace tnsping with sshpass for your use.

# which tnsping

Add the following line somewhere at the top of your script.

export PATH=$PATH:/opt/oracle/bin

NOTE: You’ll be replaceing /opt/oracle/bin with the path where sshpass was installed on your device.

24 Petr October 24, 2012 at 5:37 am

Very nice tutorial, I only have one question; What is the /incoming folder for and what is the sftp/$user/incoming from? Why are we setting the newly created user’s home folder to /incoming in step 2 (“useradd -g sftpusers -d /incoming -s /sbin/nologin guestuser”) but then creating a sftp folder in step 5 (“mkdir /sftp/guestuser/incoming”). Are steps 2 and 5 alternatives? Or what is /incoming folder in step2 the just somehow linked to the /sftp/guestuser/incoming? I appologize if that should be obvious, I’m just a poor rails programmer forced to do server admin stuff ;)

25 Petr October 24, 2012 at 7:08 am

Ok, things seem to be working even without me understanding how the /income folder gets mapped to /sftp/$user/income as the user’s home directory, but now I have another question, about allowing (possibly even only) public key access. Where do I now put the .ssh/authorized_keys? Again, maybe a stupid question, moderator if you feel like other people find it too stupid to ask, would you maybe just throw me a quick answer to my email?

Also, one thing I had to change. Instead of using /sbin/nologin as user’s terminal, I had to change it to /usr/sbin/nologin, then it started working. I am on Ubuntu 10.04.

26 Conor November 22, 2012 at 7:39 am

Works great. Thanks a lot for this.
For Ubuntu 12.04 I also had to use /usr/sbin/nologin for step 2

27 Dio December 16, 2012 at 11:59 pm

hi Ramesh, would like to ask. How about if we allow both sftp and ssh?

28 kumar January 18, 2013 at 4:52 am

with the set up i have created a user and its is working fine, but my requirement is i have to share the user say Kumar’s directory for another user Raja so that they both will be sharing the /sftp/kumar ‘s directory for raja too so that they can share files. How to do this.

29 Nic January 18, 2013 at 11:27 pm

Fyi, setting the shell to /sbin/nologin doesn’t seem to matter. The internal-sftp bit seems to take care of restricting ssh, but it seems like best practice anyway.

30 xman February 18, 2013 at 7:08 am

Works great. Thanks a lot for this.
Linux 3.4.28-2.20-desktp
openSUSE 12.2 (x86_64) – KDE 4.10.00 “release 550″ openSSH 6.0p1-2.3.3-x86_64

31 Pascual February 20, 2013 at 12:22 pm


I think one of you found a similar problem:

[root@ippbxtest ~]# service sshd restart
Stopping sshd: [ OK ]
Starting sshd: /etc/ssh/sshd_config: line 121: Bad configuration option: Match
/etc/ssh/sshd_config: terminating, 1 bad configuration options
[root@ippbxtest ~]# service sshd restart
Stopping sshd: [FAILED]
Starting sshd: /etc/ssh/sshd_config: line 121: Bad configuration option: Match
/etc/ssh/sshd_config: terminating, 1 bad configuration options
[root@ippbxtest ~]# service sshd start
Starting sshd: /etc/ssh/sshd_config: line 121: Bad configuration option: Match
/etc/ssh/sshd_config: terminating, 1 bad configuration options
[root@ippbxtest ~]# service sshd start
Starting sshd: /etc/ssh/sshd_config: line 121: Bad configuration option: Match
/etc/ssh/sshd_config: terminating, 1 bad configuration options
[root@ippbxtest ~]# service sshd stop
Stopping sshd: [FAILED]
[root@ippbxtest ~]# service sshd start
Starting sshd: /etc/ssh/sshd_config: line 121: Bad configuration option: Match
/etc/ssh/sshd_config: terminating, 1 bad configuration options
[root@ippbxtest ~]# service sshd stop
Stopping sshd: [FAILED]
[root@ippbxtest ~]# service sshd start
Starting sshd: /etc/ssh/sshd_config: line 121: Bad configuration option: Match
/etc/ssh/sshd_config: terminating, 1 bad configuration options
I am using CentOS 5.8. I have no idea on what version of openssh comes with this CentOS version so openssh must be in older versions (<5).

Any suggestion apart from upgrading openssh?

32 mike March 7, 2013 at 8:50 am

Hi Pascual

rpm -qa | grep openssh

BTW whats in your /etc/ssh/sshd_config on line 121 ?
there a slightly differences in naming of sftp, s maybe u have to change it a bit.

@all , setenforce 0 is not really a solution it’s a dirty workaround.
you should set the policies accordingly

33 Sultan April 17, 2013 at 4:03 am

Not so long ago, I told you to disabled the SELinux…. well, not anymore.. Just now I found a good tutorial about it here. for more detail and sample about SELinux, you can watch this RedHat Summit . Hopefully this is clear up what we need to enable sftp withoud disabled the SELinux.

34 Pedro Azevedo May 27, 2013 at 3:32 am


I do not want the incoming folder
I want /sftp/user
No /sftp/user/incoming

But if i change the user home to / (not /incoming), i can not do anything (like make dir, add files) because the user not have permissions.

If i cange the /sftp/user folder owner i can not login.

35 jithinsha May 29, 2013 at 5:36 am

This is the excellent post. I have tried this and its working very fine. But i tried the same with /var/www/html as the directory.

ls -ld /var/www/html/
drwxr-xr-x. 5 pop test 4096 May 25 11:07 /var/www/html/

ls -ld /var/www
drwxrwx–x. 7 root root 4096 May 21 15:28 /var/www

but when using sftp i get the output as

sftp pop@localhost
Connecting to localhost…
pop@localhost’s password:
Write failed: Broken pipe
Couldn’t read packet: Connection reset by peer

Hope someone could help me out.

36 Amit June 4, 2013 at 9:53 pm

I have created a user and added him to a group and allows access to /sftp/guestuser/incoming Now i want to allow him to access new directory and its subdirectories which is “home/admin/, How can i do it ?? Can anyone help ?

37 BurninLeo June 14, 2013 at 9:18 am

Very good tutorial, thank you!

It may prevent some disasters to add a point 6a: Check SSH configuration ( here )

If you access your server via SSH and, e.g., place the “Match Group sftpusers” order at the wrong position, you’re locked out. Nasty thing.. Running “sudo /usr/sbin/sshd -t” in advance is, therefore, a good advice :)

38 Nada_Surf July 19, 2013 at 3:42 am

Great tutorial, thanks very much!

39 Lux August 7, 2013 at 11:23 am

Nice tutorial, but a few caveats:

1) That odd “/incoming” directory in the useradd command should be the chrooted home. There should only be one home directory for the jailed user. The user’s home directory must be owned by root. You should create a directory inside that is then owned by the user and the sftp group.

2)If you’re on openssh 4.3 and you follow Suresh’s first note above, all of your users will no longer be able to ssh in. You best update to 5.4 which supports the Match keyword.

40 Andrea Garbarini October 16, 2013 at 6:56 am

Great howto, thanks, but the home dir for the sftp user (in etc/passwd) should be relative to the system’s root, and NOT the chrooted environment. Took me hours to figure this out, public key authentication was not working because of sshd looking for the authorized_keys file in the wrong location (and this was not clear at all from sshd debug messages)

41 Shahil October 25, 2013 at 10:39 am

Dear Sir,

Can I use same home dir for Multiple users with case of chroot sftp ??

42 Nurettin November 1, 2013 at 4:51 am

Thanks for that great article.

Now i need detailed logging. I’m using rhel 6.4. How can i accomplish that ?

43 Girish December 20, 2013 at 1:16 pm

Nice article.. worked well on Centos 6.2.

Thank you!


44 vinay December 24, 2013 at 4:36 am

after follow all the above step when i test chroot sftp it shows error:

guestuser@thegeekstuff’s password:

Write failed: Broken pipe
Couldn’t read packet: Connection reset by peer

help me guys
thanks in advance

45 Michael Curtis March 10, 2014 at 5:23 am

We had the broken pipe error. We hadn’t made the /incoming folder. We had tried to use our own structure and got a bit confused :)

46 mehar April 8, 2014 at 10:02 am

After doing this i am not able to do ssh with root user to server :( i am able to do sftp with chroot to new ftp user

what could be the reason as i didn’t do anything with root user..
now i have post the ticket to rackspace to check the same..
but how can i set chroot jail to single user so that can access server with ssh root

47 Bob May 22, 2014 at 1:57 pm

the next tutorial should be how to set up pre-shared keys for the sftonly users. So ??

48 Chris July 2, 2014 at 2:11 pm

Hey, Just wanted to thank you for making this available and so easy to follow.

I found by accident that the landing folder can’t be owned by the chrooted user. I had put chown -R guestuser:sftpusers /myfolder/ and got
Network error: Software caused connection abort
until I changed myfolder back to root ownership.

Thanks again.

49 Lucas Leite August 21, 2014 at 8:37 am

It work’s for me. Great tutorial!

50 Antony October 2, 2014 at 3:27 am

Great post. I got permission denied on Centos and found the following link really helpful: here – in short you can enable/disable selinux which allows access. Hope that helps.

51 Anonymous October 16, 2014 at 5:37 pm

Hi , I have created two users p10 and d10.
uid=11010(d10) gid=201(dba) groups=201(dba)
uid=11009(p10) gid=201(dba) groups=201(dba),11009(sftpusers)

In sshd_config, I have mentioned
Match Group sftpusers

But still I am able to do sftp with d10 user.

Kindly suggest.

Harshad More

52 leonardo December 4, 2014 at 5:13 pm





userdel -r $USERNAME
umount /sftp/$DIRBET/$USER_DIR/incoming

useradd -g $GROUP -d /incoming -s /sbin/nologin $USERNAME
passwd $USERNAME

mkdir /sftp
chown root:root /sftp

mkdir /sftp/$DIRBET
chown root:root /sftp/$DIRBET

mkdir -p /sftp/$DIRBET/$USER_DIR/incoming
chown root:root /sftp/$DIRBET/$USER_DIR

mkdir -p /var/www/html/repository/uploadcsv/$USER_DIR
chown $USERNAME:$GROUP /var/www/html/repository/uploadcsv/$USER_DIR
mount –bind /var/www/html/repository/uploadcsv/$USER_DIR /sftp/$DIRBET/$USER_DIR/incoming

echo ‘Match User ‘ $USERNAME >> /etc/ssh/sshd_config
#echo ‘Match Group ‘ $GROUP >> /etc/ssh/sshd_config
##echo ‘ ChrootDirectory /sftp/%u’/ >> /etc/ssh/sshd_config
echo ‘ ChrootDirectory /sftp/’$DIRBET/$USER_DIR >> /etc/ssh/sshd_config
echo ‘ ForceCommand internal-sftp’ >> /etc/ssh/sshd_config
##echo ‘ AllowTcpForwarding no’ >> /etc/ssh/sshd_config

tail /etc/ssh/sshd_config
grep $USERNAME /etc/passwd
ls -ld /sftp/$DIRBET/$USER_DIR/incoming
ls -ld /sftp/$DIRBET/$USER_DIR
ls -ld /sftp/$DIRBET
ls -ld /sftp

setenforce 0
service sshd restart
sftp $USERNAME@localhost

53 Anonymous December 8, 2014 at 12:06 am

how to restrict the other directory only access the that particular sftp directory

54 Scott Genevish December 12, 2014 at 2:33 pm

On step 2, you may want to add the -M option:

useradd -M -g sftpusers -d /incoming -s /sbin/nologin guestuser

Otherwise it will create an /incoming folder at the root. It’s not a huge problem (and the extra folder can be safely deleted).

Leave a Comment

Previous post:

Next post: