Setup of a chroot'd SFTP only server


The SSH File Transfer Protocol or SFTP is a network protocol providing file transfer and manipulation functionality over a reliable, encrypted data stream using SSH version 2. A common misconception is SFTP is simply FTP run over SSH; the truth is SFTP is a new independent protocol designed from the ground up by the IETF SECSH working group and thusly not compatible with ftp. SFTP server and its support tools are built into OpenSSH by default.


provide SFTP only access to users (no ssh or scp) restrict users to their home dir (chroot) no libraries or other server support files in users' home dir allow file upload and download access no executable interactive shell access keep maintenance to a minimum when upgrading OpenSSH

The easy way and the hard way

Depending on the version of OpenSSH you have installed depends on how much work you need to do to get a secure sftp server setup.

Need help setting up a fast and secure OpenSSH server or assistance with the ssh client? Check out our OpenSSH configuration "how to".

OPTION 1: Install OpenBSD v4.3 (OpenBSD v4.2 -current) or higher with ChrootDirectory

First, make sure you have the ChrootDirectory option in the man page of the openssh server you are going to use. If the option is not available then you need to update your version of openssh. If you are using OpenBSD 4.2 -stable you can always download the -current CVS source tree and build openssh from there. If you need assistance setting up the cvs tree take a look at Patching OpenBSD kernel and packages "how to".

Next, add the following lines to your sshd_config file. The "recommended directives" are just good security items you may want to use. The "sftp directives" are what is needed to get the sftp server working.

The new Subsystem called "internal-sftp" was specifically made by the OpenBSD group for the purpose of chrooting sftp users. The next option will "Match" the user we will call "ftp" to be forced into the chroot at login. The order of loading the Subsystem before the ForceCommand is critical. If you reverse the order you will get errors when sshd tries to start and it will die.

##### cat /etc/ssh/sshd_config
## optional, but recommended directives
AllowTcpForwarding no
ClientAliveCountMax 3
ClientAliveInterval 0
Compression delayed
LoginGraceTime 60s
LogLevel DEBUG3
MaxAuthTries 6
PasswordAuthentication yes
PermitEmptyPasswords no
PermitRootLogin no
PermitTunnel no
PermitUserEnvironment no
Port 22
Protocol 2
StrictModes yes
SyslogFacility AUTH
TCPKeepAlive yes
UseDNS no
UsePrivilegeSeparation yes
X11Forwarding no

## sftp directives
# override default of no subsystems
#Subsystem      sftp    /usr/libexec/sftp-server
Subsystem       sftp    internal-sftp

Match User ftp
    ForceCommand internal-sftp
    ChrootDirectory /ftp_jail

NOTE: If you are going to allow sftp _only_ logins for the user then they DO NOT need a shell. You can add the user and set the shell as /sbin/nologin. When the user logs in with sftp their shell will be internal-sftp as set by sshd.

Next, you need to setup the directory where the user "ftp" will be chrooted. For simplicity we are going to make the directory called "/ftp_jail". For the internal-sftp server to allow logins, the directory permissions must be setup correctly. If not, the sshd server will start, but the "ftp" user will not be allowed to log in.

Make the "/ftp_jail" directory. Set the ownership as "chown root:ftp /ftp_jail" and "chmod 750 /ftp_jail". The directory will look like this:

drwxr-x--- root ftp 1000 Jan  1 10:10 /ftp_jail

This will make a read-only, chrooted directory perfect for people to come in and get stuff, but never write. By changing the permissions on the directory you can change the level of access you give to the "ftp" user. For example, you could make a directory /ftp_jail/uploads that allow people to write in. Then you can moderate what gets copied into the read-only /ftp_jail area. Remember that if a user can write in a directory then they can also delete anything in that directory.

Thats it. All done. If you have any questions please scroll to the bottom of this page.

Want more speed? Make sure to also check out the Network Speed and Performance Guide. With a little time and understanding you could easily double your firewall's throughput.

OPTION 2: Install OpenBSD 4.2 or earlier with mount options on the sftp partition


OpenBSD v4.2 with OpenSSH v4.7

What needs to be done:

build and install openssh after applying the sftp-server patch build and install the sftpsh shell apply changes to chroot'd, sftp only users

As an added layer of security one can make a partition limiting user options. OpenBSD supplies mount options denying device files, suid calls, and execution of files with the exec bit set on a partition. Apply the following mount options "rw,nodev,nosuid,noexec,softdep" to the partition the chroot'd user's home directory will exist. Edit the /etc/fstab file and add the options to the partition sftp will chroot on. For example:

  # cat /etc/fstab | grep chroot
  /dev/wd0c /chroot_dir ffs rw,nodev,nosuid,noexec,softdep 1 2

Step 2: getting the OpenSSH source files

Make the directory tree /usr/src/usr.bin/ and change to that directory. Download the latest openssh source tar file from OpenBSD and untar it. Change directory in to the ssh directory.

  mkdir /usr/src/usr.bin/
  cd /usr/src/usr.bin/
  tar zxvf openssh-4.6.tar.gz
  cd ssh

Step 3: patch OpenSSH source with the sftp-server chroot patch

The only change to the openssh source is additional code to the sftp-server.c file making upgrades to OpenSSH in the future a simple task. The code will look for the string "/./" in the home directory path of the user in /etc/passwd. If the string is found the user will be chroot'd to their home directory. The following file is the patched version of the sftp-server.c file. If you have openssh v4.5 or v4.6 you can simply drop this in the source directory "/usr/src/usr.bin/ssh/" replacing the original sftp_server.c file. You can also download the patched sftp_server.c file and diff it against your own downloaded version. This way you can look at the proposed changes.

Download the patched file: sftp-server.c

Step 4: build and install OpenSSH

Before building you _may_ want to change the version variable reported by the server to the client. There is no reason the client needs to know what version of openssh we are running. To edit the publicly reported version open the version.h file and change the SSH_VERSION string.

  #define SSH_VERSION     "OpenSSH_4.6" 
                 ...changed to something different...
  #define SSH_VERSION     ""

To build openssh change to /usr/src/usr.bin/ssh/ directory and execute the following to make openssh and install the binaries:

  make clean && make obj && make cleandir && make depend && make && make install

Changing the version variable is optional, but highly recommended. When your machine is scanned the first piece of information a bot looks for is the version number of he ssh server. Do not give out any information that the client does not explicitly need. The ssh server and client will negotiate fine without the version number.

Step 5: suid the sftp-server

The user is going to be chroot'd into their home directory so we need to execute the sftp-server suid. Once the sftp-server is executed the binary will drop privileges to the chroot'd user. If the sftp-server process is ever compromised, permissions no higher than the chroot'd user could be obtained.

  chmod +s /usr/libexec/sftp-server

Step 6: build and install the sftpsh shell

The sftpsh shell is the wrapper we will use to deny all connections other than sftp. Sftpsh is the shell the chroot'd user will use when they log in.

Download shell wrapper file: sftpsh.c

Edit sftpsh.c and take a look at the variables at the top of the script. Make sure you set SFTP_BINARY to the proper path where sftp-server is found. Also, you may want to edit the DENY_MESG to something more appropriate for your system. This is the message a remote user will see upon a failed login with ssh or scp.

  Build and install sftpsh:  gcc sftpsh.c -o sftpsh;cp sftpsh /bin/sftpsh

Once sftpsh is built and installed add /bin/sftpsh to /etc/shells so you can easily apply it to your users.

Step 7: setup the "sftp only" users

To restrict a user to a the chroot'd sftp only server simply add "/./" to the end of their home directory path and change their shell to /bin/sftpsh. For example our "test" user's home directory and shell are the following according to /etc/passwd:

  test:*:1001:1001:sftp test,,,:/chroot/test/./:/bin/sftpsh

Step 8: testing the server

The openssh server has been patched and the sftpsh shell has been installed. Check the sshd_config file and make sure the line with sftp-server is uncommented. Make sure to shut down sshd and restart it. Sftp to the server with the user name and password of the user you have chroot'd in /etc/passwd.

  sftp user@machine

You should be able to log in without issue. Now, try to change directory up and out of the home directory. This should fail as the home directory is the chroot'd environment. You can type "?" in the cli to see what commands are allowed. Take a moment to familiarize yourself with what a user can do in the environment. Make sure you know what commands are allowed through the sftp client and whether they will cause your environment any issues. Users can be amazingly destructive even with their own files.

Now try to ssh to the machine and scp a file to/from the machine.

  ssh user@machine
  scp local_testfile user@machine:.

Both ssh and scp should fail and the DENY_MESG string you set in sftpsh should have been displayed and your client immediately disconnected.


We have built a secure, encrypted file server allowing a user to send and receive files through sftp only. Ssh and scp are denied to only chroot'd users. The server will not allow the execution of programs or running of any system binaries by the client. As an added bonus we have removed all of the active/passive port problems associated with standard ftp and ftp though ssl. Sftp will run through firewalls, uses a fully stateful connection scheme and works over most questionably setup networks.

There are many programs that will allow your users to access the sftp server. OpenSSH by the OpenBSD group supplies a CLI sftp client by default. Windows users can use the graphical WinSCP, SshSecureShell or BitKinex or check on for example. MacOSX users can use the openssh cli or a graphical GUI called "Fugu" which works quit well.

Users wanting to use scripts with sftp should have no problems. For a password less environment they will need the use of ssh-keys. For added security it is suggested that you limit the connection rate of ssh users. With pf you can easily limit the connections to 5 connections per 30 seconds for example. You can also add an abusive user to a 000033list automatically with the same stateful tracking options. Check on the main page of for pf.conf examples and instructions.


Can I set the umask for sftp users?

Setup the "Match" block for any user in the group "sftponly" that wil sftp in and ChrootDirectory them into their home directory.

user@machine# vi /etc/ssh/sshd_config

Match   Group sftponly                                                                                                       
        ChrootDirectory %h                                                                                                   
        ForceCommand internal-sftp                                                                                           
        PasswordAuthentication yes                                                                                           

After the user logs in the umask needs to be set. Since you are using the ForceCommand directive for internal-sftp you can not use .ssh/rc or .ssh/environment.

So, you can create a new class in login.conf(5) called "sftponly", specify the umask= parameter to it and add any user that is going to sftp to the sftponly group in /etc/group .

user@machine# vi /etc/login.conf

# sftp users 

Can I allow or deny users the use of ssh-keys?

Yes. Since the user is going to be chroot'd in their home directory they can use the ".ssh/authorized_keys" file. All the user would need to do is make a authorized_keys file (perms 640) with the keys already inserted. Then the user would make the ".ssh" directory (perms 700) on the server and upload the "authorized_keys" file in the ".ssh" directory. To deny the use of keys simply make the ".ssh" directory (perms 700) as root and the user will not be able to access it.

Why do you use sftp instead of scp?

Sftp has a limited shell interface like standard ftp. This allows users to log in and make changes to the directory structure like making directories and file removal.

Errors you may encounter:

"Received message too long..." and disconnection When you sftp to the server, the server reports "Received message too long 168660913" and then disconnects. The large number at the end of the error may be different. This error is reported if the server sends data, commands or errors to the client when the client is not expecting it or if the binary being called is not executable. During this setup you will see this error if the "SFTP_BINARY" path in the shell "sftpsh" is not correct. To fix:
edit the shell program "sftpsh.c" set #define SFTP_BINARY "/usr/libexec/sftp-server" to the correct path recompile and install with "gcc sftpsh.c -o sftpsh;cp sftpsh /bin/sftpsh"

Special thanks to for the for the ftp-server.c patch.

Questions, comments, or suggestions? Contact