Creating a chrooted sftp-only ssh user
I wanted to set up an easy and secure way to use the storage on my server as a personal “cloud storage”. I also wanted it to be isolated from everything else on the server. To do this, I used a chrooted sftp-only ssh user. There are probably other ways to do something similar, but I went for this option because I didn’t need to install additional packages.
Prerequisites
You only need a Linux server with ssh. I’m using Ubuntu Server 18.04 LTS with OpenSSH, but this should work on any modern Linux distribution.
Setting up our user
We’re going to need a separate user on our server. I’ll be calling mine sftponly
, but
you can use whichever name you want.
$ sudo adduser --disabled-password --shell /usr/sbin/nologin sftponly
This creates a user without shell access and without a password. It can only login using ssh key-based authentication.
This is also the moment to add your ssh public key to the authorized_keys
file of the
newly created user:
$ mkdir /home/sftponly/.ssh
$ echo "YOUR PUBLIC KEY HERE" >> /home/sftponly/.ssh/authorized_keys
We also create a path for the chroot:
$ mkdir -p /srv/sftp/chroot
Make sure this directory is owned by root and not writeable by any other group or user:
$ ll /srv/sftp
drwxr-xr-x 3 root root 4096 jan 29 21:46 chroot
This is required by the ChrootDirectory
option for sshd that we will be using. From
the sshd_config(5)
man page:
ChrootDirectory
Specifies the pathname of a directory to chroot(2) to after authentication. At session startup sshd(8) checks that all components of the pathname are root-owned directories which are not writable by any other user or group. After the chroot, sshd(8) changes the working directory to the user’s home directory. Arguments to ChrootDirectory accept the tokens described in the TOKENS section.
If sshd gives any bad ownership or modes for chroot directory
errors, double check that
you have set up the ownership correctly according to the sshd_config(5)
. Note that you
may also get broken pipe
errors if the permissions are incorrect.
Editing our sshd configuration
Next we have to edit our sshd_config
. Find the line
Subsystem sftp /usr/lib/openssh/sftp-server
and change it into
Subsystem sftp internal-sftp
This makes it possible to use the ChrootDirectory
option without any further configuration.
And then we add the last part of our configuration. For our specific user, we set up the chroot directory and force sftp. For security, TCP forwarding and ssh agent forwarding is also disabled.
Match User sftponly
ChrootDirectory /srv/sftp/chroot
ForceCommand internal-sftp
AllowTcpForwarding no
AllowAgentForwarding no
If you want the user to only have read-only access, use ForceCommand internal-sftp -R
instead.
Results
Now if we just try to ssh we’ll be kindly reminded that we can only use sftp:
$ ssh sftponly@example.com
This service allows sftp connections only.
And sftp obviously works like charm:
$ sftp sftponly@example.com
Connected to example.com
sftp>
And we can see that we’re working in a chroot:
sftp> pwd
Remote working directory: /