I feel like I've gone through every SFTP/Chroot tutorial on the Internet, and not found what I am looking for (or, at least, none of them have produced the right results). Here's my specifics:

  • I will be creating a lot of individual user accounts via script. So any solution that requires me to very delicately hand edit files on a user-by-user basis is not a good one.
  • Each of these users will be given a directory in the folder /var/www/html/USER, where USER is their username. They should have total write access to that directory, and be able to create and edit sub-directories, but they should be entirely locked out of any directories that are higher on the file tree (they should not be able to list, much less edit, /var/www/html/ or /var/www/ or /var/, etc.)

That's it. Seems simple, right? And yet most of the examples I have seen are about locking all SFTP users into a single, shared directory, or require you to "jail" your user to their /home/USER directory (which won't work for the web service). I don't want that.

I am doing this on Ubuntu 16.04, on a fresh AWS EC-2 instance.

The two approaches I have tried, in vain:

  • Setting the user's HOME to /var/www/html/USER, Chroot jailing them to HOME. For whatever reason, this doesn't seem to work — it results in SFTP just refusing to connect.

  • Setting up a standard HOME directory for the user (e.g. with adduser), creating the user's web directory, Chroot jailing them to the web directory. I've just not managed to get this working despite days of trying — the SFTP accounts still end up tunneling into the HOME directory and that often means they are rejected by the Chroot jail.

What has ended up happening is either users have WAY too much freedom, or they are locked out entirely. I've never managed to get it into a situation where the user can only see the right directory, AND are able to edit it. I have tried every chown setting on that directory (e.g., user:user, user:sftp, root:root), and permission setting, and it seems to have had zero effect. I'm missing something here that is either obvious or deep.

Some added details — here's one of my attempts.

Here are the relevant parts of /etc/ssh/sshd_config:

Subsystem sftp internal-sftp
Match Group sftp
ChrootDirectory %h
X11Forwarding no
AllowTcpForwarding no
ForceCommand internal-sftp

Which matches what most guides say you should do.

I create a new user:

adduser --disabled-password -gecos "" --ingroup sftp --shell /usr/sbin/nologin --home /var/www/html/testuser testuser

Which says:

Adding user `testuser' ...
Adding new user `testuser' (1001) with group `sftp' ...
Creating home directory `/var/www/html/testuser' ...
Copying files from `/etc/skel' ...

And I then give them a password with passwd.

I then try to log in:

sftp testuser@myserver
testuser@myserver's password: 
packet_write_wait: Connection to myserver_ip: Broken pipe
Connection closed

Which seems to be due to the Chroot jail setting and not related to any other obvious server setting. If I comment out the ChrootDirectory, it connects fine:

sftp testuser@myserver
testuser@myserver's password: 
Connected to myserver.
sftp> pwd
Remote working directory: /var/www/html/testuser

But I do that, the sftp user can exit their directory and wander all over the server, doing whatever they please. Not good!

I have also tried setting

 ChrootDirectory /var/www/html/%u

And it doesn't change anything that I can see (same "Broken pipe" error as before). (And yes, I am restarting the ssh server every time I make a change.)

These are the current settings for the user folder:

drwxr-xr-x 4 testuser  sftp 4096 Aug 29 15:00 testuser

Some instructions say for Chroot to work, you need to

chown root:root /var/www/html/testuser

But I still get the "Broken pipe" error with the ChrootDirectory set. Changing the permissions to 777 doesn't change that, either. (/var/www/html is owned by root:root, as is /var/www/ and /var/)

Other things I have tried with /etc/ssh/sshd_config:

  • changing it to Subsystem sftp /usr/lib/openssh/sftp-server and commenting out ForceCommand internal-sftp (no perceivable change)

  • Commenting out UsePAM yes (someone reported this helped, but it just makes sftp server reject all connections immediately -- "closed by remote host")

  • "[...] or require you to "jail" your user to their /home/USER directory (which won't work for the web service). I don't want that. [...]": Couldn't you just set $HOME to /var/www/html/$USER? Edit: Ah, sorry, you tried this already...
    – gxx
    Aug 29, 2017 at 13:04
  • Yeah, I have no idea why that doesn't work, but it was the first thing I thought of. If anyone knows WHY that doesn't work, I'd love to hear it... maybe there is a way around it. It seems like the simplest solution.
    – nucleon
    Aug 29, 2017 at 13:10
  • That looks like all steps are correct, I don't have any idea why this isn't working. That's really strange. >Couldn't you just set $HOME to /var/www/html/$USER? Edit: Ah, sorry, you tried this already... That was and my only 1 idea.
    – fopsik
    Aug 29, 2017 at 14:02
  • I've added some more details on what I've tried, if that helps. Clearly I'm doing something wrong, I just can't figure out what.
    – nucleon
    Aug 29, 2017 at 15:06

2 Answers 2


OK, I finally got it working. There were a few things I was doing wrong, and obviously my attempts to do it over and over again screwed up some settings so I just hosed the instance and started from scratch.

The main issue seems to be that you can't make the Chroot'ed directory a writeable one. So it can't be your main web directory. I had been thinking about this all wrong, trying to make user accounts off of my main Apache directory. That's not right — what you do is you make the user accounts in a standard user directory (/home/jimmy), make a www (or public_html or whatever) folder within that directory, make the user directory itself (in this case, /home/jimmy/) owned by root, and make the writable directory (/home/jimmy/www) owned by jimmy and the Chrooted group (e.g. "sftp" in my examples above). Then you set the ChrootDirectory to %h (in this case, /home/jimmy). Jimmy won't be able to do anything within the directory /home/jimmy/, but he can put files into /home/jimmy/www. To make this usable, you then set up userdir in Apache and tell it to use those www folders as user folders.

Now it works!

  • Glad you got it sorted out, +1.
    – gxx
    Aug 30, 2017 at 10:33
  • You confirm what I also understood so far. I'm just wondering that it has to be like that. A SFTP user logs in and has to cd into www at first - instead of just being direclty in the www folder. Is there no way to let the user be in the actual directory straight away??
    – robsch
    Oct 8, 2019 at 13:17

jail-shell can meet this requirement, i think. It's easy to use.



You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .