Creating a chrooted SFTP user can often be a bit tricky when it comes to ensuring they’re correctly restricted, whilst also still able to read/write files as needed. One way I’ve gotten around this is with bind mounts.
Lets create a new user as an example, for our site example.com
:
mkdir /home/example.com
chmod 755 !$
chown root. !$
useradd -d /home/example.com -s /bin/false -G chrootsftp,www-data example.com
The group name we specify here isn’t important, as long as it’s easily recognisable, so chrootsftp
is as good as any.
We then add a match group block to /etc/ssh/sshd.config
and reload ssh:
Match Group chrootsftp
ChrootDirectory %h
PasswordAuthentication yes
ForceCommand internal-sftp
The exact bind mount will depend on your site configuration, but I often use htdocs
as a public space for my web files:
mkdir /home/example.com/htdocs
We then bind mount this new directory to the real site public directory, which in my case is at /srv/example.com/htdocs
:
mount -o bind /srv/example.com/htdocs /home/example.com/htdocs
To persist on reboot, add the following entry to /etc/fstab
too:
echo "/srv/example.com/htdocs /home/example.com/htdocs none bind 0 0" >> /etc/fstab
Make sure the setgid
bit is set on the site’s public directory downwards, to force any new files or directories created by this user to have a group matching the parent directory (e.g. www-data
), and not that of the user example.com
:
find /srv/example.com/ -type d -exec chmod g+s {} \;
Finally, grant this new user appropriate permissions on the site directory:
setfacl -R -m u:example.com:rwx /srv/example.com/htdocs/
setfacl -R -d -m u:example.com:rwx /srv/example.com/htdocs/
Optionally we can grant the group full rwx
permissions instead, but the above option will be safer in most cases, unless you’re restricting this new user to a single directory within the site (for uploading images for example):
setfacl -R -d -m g::rwx /srv/example.com/htdocs/shared_images/
With this, the chrooted SFTP user should be able to login and modify only the directories you’ve specified.