Every two weeks I send out a newsletter containing lots of interesting stuff for the modern PHP developer. You can expect quick tips, links to interesting tutorials, opinions and packages. Want to learn the cool stuff? Then sign up now!

Let your clients use sftp on a Forge provisioned server

A few years ago all the projects I worked on were served on a shared hosting environment. It was quite common that a client had ftp access to server to upload some files. A control like Cpanel or Plesk made it really easy to create some ftp accounts.

Fast forward to today. Most projects are hosted on their separate DigitalOcean droplets provisioned by Forge. Even the smallest droplet has a whopping 20 GB of diskspace. An ftp-server is not installed by default. That’s probably a good thing because ftp is an insecure and antiquated protocol. In this post I’d like to explain how you can help a client that wants ftp-like functions.

Our goal is to give a client read and write access to a single directory. We will make sure that the client cannot go outside that directory. We’ll also prohibit the client from executing any shell commands. Instead of ftp we’re going to use a more secure protocol: sftp. Let’s do this!

The first thing you’ll have to is to add a unix user. In the remainder of this post we’ll assume that our client is named Bob.

sudo adduser bob

You will be prompted for a password and some general user information. After completing this command the homedirectory for Bob will have been created at /home/bob.

Next up we are going to make sure that this user is not allowed to use a shell:

sudo usermod -s /bin/false bob

If Bob will try to login via ssh he will immediately be logged out.

Now we are going to “chroot” Bob. This is the wikipedia definition:

Chroot is an operation that changes the apparent root directory for the current running process and their children. A program that is run in such a modified environment cannot access files and commands outside that environmental directory tree. This modified environment is called a chroot jail.

Chrooting Bob will make sure that when he logs in he will not see that he’s in /home/bob directory. Bob will see that directory as his root. He will be able to create files and directories in only that directory. He will see nothing outside of it.

Here are the commands to set the permissions necessary to chroot Bob and to allow him full access to an uploads directory.

sudo chown root:bob /home/bob
sudo chmod 755 /home/bob

sudo mkdir /home/bob/uploads
sudo chown bob:bob /home/bob/uploads
sudo chmod 755 /home/bob/uploads

Right now Bob cannot login, we made sure of that by setting his shell to /bin/false Let’s enable sftp for poor little Bob.

Inside /etc/ssh/sshd_config you should comment out this line by adding a “#” before it:

Subsystem sftp /usr/lib/openssh/sftp-server

Add these lines at the bottom of the same file:

#Enable sftp
Subsystem sftp internal-sftp

Match User bob
   #set the homedirectory as root
   ChrootDirectory %h

   ForceCommand internal-sftp
   X11Forwarding no
   AllowTCPForwarding no

   #enable loging with a password
   PasswordAuthentication yes

Reboot ssh to activate those changes:

sudo service ssh restart

Aaaaand we’re done. Now Bob can use an application that has support for sftp (on OSX I highly recommend Transmit) to login with username bob and the chosen password.

Happy uploading!

Freek Van der Herten is a partner and developer at Spatie, an Antwerp based company that specializes in creating web apps with Laravel. After hours he writes about modern PHP and Laravel on this blog. When not coding he’s probably rehearsing with his kraut rock band.
  • Vincent N.

    Nice and clear tutorial! 🙂
    Putting this in Forge as a recipe could be useful, then you don’t have to deal with this small but repetitive task.

  • Tihomir Opacic

    As always, great stuff. If you want to give permission to a user to upload to website document root folder or it’s subfolder you won’t be able to chroot to /home/forge/sitename.com as all components of a path must be owned by root to prevent a user from escalating their privileges and becoming root. Workaround is to copy the sitename.com over to /home/bob, set the permissions accordingly, and than symlink to that folder like ln -s /home/bob/sitename.com /home/forge/sitename.com

  • Pingback: Setup sFTP on a Forge provisioned server - Laravel News()