Restricted SFTP in Mac OS X Leopard

On occasion you may want to exchange data with someone else. You'd like to grant that person access to your system (or network) but in such a way that the person has limited access to other areas of the system (or general resources on your network). This article will show you how to setup a chrooted jail that restricts the user to only SFTP on Mac OS X Leopard. It further limits the user so that they cannot traverse the filesystem outside the bounds you specify.

If you the exchange is one way (for example you want someone to be able to download a file), you can sometimes post it to a website and send them the URL. But sometimes you want to be able to exchange files back and forth. Of course for small files, email is the most obvious way to do this these days.

Another way that is increasingly used is to restrict the user to a specific portion of the computer that serves as the exchange intermediate (sometimes called a chrooted jail). FTP servers often offer such a facility, but more often people are moving away from FTP to other mechanisms. There are third party applications such as RSSH that can be used to create chrooted environments using secure transfer methods like SSH. They work, but sometimes they can be difficult to set up (or are not supported on the platform of choice).


Mac OS X Leopard 10.5.5 or higher
Server or Client version
Remote login enabled (SSH/SFTP)
A user account that is allowed to remotely access the system (in this example the user account name is bubbrubb)

All commands are performed as root (or via sudo). If root is disabled on your system, you can use sudo or 'sudo su' to root.

An important restriction for this to work, is that where ever your files exist on the computer the path to those files must be owned and only be writable by root. A simple example:


The root directory (/) needs to be owned by root, and only writable by root. Similarly the directory foo must also be owned by root and only writable by root. The group and everyone permissions can be readable or executable, just not writable.

Another example. Say you want your files to be stored on a drive separate from your main OS drive:


Again, /, /Volumes and the volume Storage must all be owned by root and only writable by root.

If you are wondering how a user would write to the disk if only root owns it, I'll explain that in a bit.

Storage Location Setup

For this example we'll use /Volumes/Storage. (Note, you can do this via symlinks too, but for now, we'll just use the disk structure that Mac OS X sets up on disk insertion).

sudo su to root:

chmod g-w /
chmod g-w /Volumes
chmod g-w /Volumes/Storage
chown root /Volumes/Storage

Make a directory for your user:

mkdir /Volumes/Storage/bubbrubb
chown bubbrubb /Volumes/Storage/bubbrubb
chmod 700 /Volumes/Storage/bubbrubb

The above does the following:

1) Create a path to the general storage location that only root can modify. (this will not work, if this isn't true, the connection will outright fail).

2) Create a directory that bubbrubb owns and can write to. We restrict the other permissions so that only user bubbrubb can read and write there (you could log into the server using bubbrubbs account OR modify the group permissions so that others accounts in that group can read and write there too). The important part is that all folders leading up to that one are writable only by root.

SSH Remote Access

First test that the user account you want to restrict can ssh into your system. If that works, then continue. If not, figure out why, then:

cp /etc/sshd_config /etc/sshd_config.bkup

Then edit sshd_config commenting out the line:

Subsystem       sftp    /usr/libexec/sftp-server

and adding the line:

Subsystem sftp internal-sftp

Then add a block similar to the follow (substituting the User name for the appropriate name on your system):

Match User bubbrubb
        X11Forwarding no
        AllowTcpForwarding no
        ChrootDirectory /Volumes/Storage

On Leopard Server the match criteria take effect immediately (that is you do not need to restart the service), you may need to on Leopard Client.

Note that in the above Match statement we place the user into the directory one level up from where they can write. Remember, that the path that the user logs into by default can only be writable by root. Once the user logs in, they cd to their directory and can then write files there.

User connections and uploading files

First try connecting via ssh:

mymac:~ bubbrubb$ ssh

The connection will hang after you type in your password. Press control-C to cancel the connection. If it goes through some setting didn't take effect.

Then try with sftp:

mymac:~ bubbrubb$ ssh
sftp> cd bubbrubb
sftp> put testfile
Uploading file to /bubbrubb/testfile
testfile                                                                                                                                       100%    0     0.0KB/s   00:00

sftp> get testfile
Fetching /bubbrubb/testfile to testfile

If you made it this far, then you have successfully set up your chrooted jail.


This does not appear to work on systems running Leopard earlier than 10.5.5. I tried this using a system running 10.5.4 and it failed. I didn't do an exhaustive test. YMMV.

I can't stress this enough. The path permissions up to and including the entry point for the jail MUST be owned by root and writable only by root. If not, the connection will fail.

You can increase the verbosity of the sftp connection using the -v, -vv, or -vvv flags with SFTP.


Comment viewing options

Select your preferred way to display the comments and click "Save settings" to activate your changes.


This cannot work in 10.5.4 or earlier (at least not out of the box), because it comes with an older version of OpenSSH, that does not support chroot.

This is a great chrooted

This is a great chrooted sftp method and works, but it seems to have one major drawback (at least for me).
If you have your chroot directory on a disk other than the startup disk, and therefore you make /Volumes 'rwxr-xr-t' ie non-writable by anyone except root, then you get a rather nasty side-effect.
No afp volumes will mount any more. You get the message 'The volume could not be mounted' on attempting to mount any afp volume.
If I return /Volumes to rwxrwxrwt using 'chmod 1777 /Volumes', I can once again mount afp volumes.
I wonder if this can be worked around...?

What about the permissions of others?

Shouldn't you also run:

chmod o-w /
chmod o-w /Volumes
chmod o-w /Volumes/Storage

The /Volumes directory in particular had write permissions for others by default on my installation that would need to be changed if it is to be only writable by root.

Instead of chmodding

Instead of chmodding /Volumes, why not create a new chroot folder such as /chroot/Volumes and symlink your drives from the real volumes to the chroot one?

If you're using network drives i guess you'd have to chmod volumes instead.

No such file or directory

I am using a Mac mini (OS X Leopard 10.5.6 Client) to host some development web sites. I have followed the instructions on this page (substituting /Volumes/Storage/ with /Users). For some reason though, whenever I try to connect to SSH using the terminal, I get the following messages:

wm-mb-travis:~ Travis$ ssh [username]@[hostname]
Last login: Tue May 26 23:17:59 2009 from [RouterIP]
/bin/bash: No such file or directory
Connection to [hostname] closed.

(Of course, I blanked out the actual usernames, hostnames, and IP addresses above.)

The Console does not display any kind of errors to help me (both on the "Server" and Client). Any ideas on what could be wrong?

Permission denied

I get:
/bin/bash: Permission denied
Connection to closed.

Any thoughts appreciated

(Server name and user name amended of course)

Request for subsystem 'sftp' failed on channel 0

Request for subsystem 'sftp' failed on channel 0
Couldn't read packet: Connection reset by peer

So.... what's wrong now? Help! Thank you somebody.

"chmod g-w /Volumes" running

"chmod g-w /Volumes"

running Repair Permissions will break this (change it back)... at least it did on my 10.5.7 box.

problems when logging in

I followed this and like others had problems logging in when done. The part that seems to cause the problem is this:
ChrootDirectory /Volumes/Storage

I worked around this by removing that line and then downloading Server Admin Tools and using Workgroup Manager to create the users. These are the steps I followed to get it working

  • Open Workgroup Manager
  • from the Server menu choose View Directories
  • click OK when it tells you that you are working in a directory node that is not visible to the network
  • click the lock in the upper right hand corner and put in your admin credentials
  • Click New User in the top button bar
  • Enter a name and password
  • Click the Home tab
  • Click the plus button at the bottom
  • enter the path to the shared folder, i.e. /Volumes/Storage
  • click Save

Workgroup Manager does attempt to setup a Home folder there, but it fails. Since I only want these users to have SFTP access and not a folder structure with /Movies, /Library, etc, this is actually better for me.

This seems to work for me.

This piece does a nice job

This piece does a nice job of showing you how to execute an SFTP file transfer. When you want a little more security, this is often a great tactic.