Create a secure backup solution with chrooted SFTP
Secure Shell (SSH) is a very versatile tool that allows you to connect remotely in a secure manner. One of its most common uses is to transfer files and in these cases it can be confusing for users to see the entire host file system. It also makes the host system more vunerable when exposed to all users. In *NIX systems, however, there is a possibility to change the root of the file system so that a user for example sees their own home directory as a virtual root. Up until version 4.9 of OpenSSH it has been quite complex to setup a chrooted environment, but with later versions of OpenSSH it has become a lot easier, provided you only need to be able to transfer files over the SSH protocol (i.e. SFTP, no shell access). This article provides step by step instructions on how to set up a chrooted SFTP solution.
Assumptions
I have been using Ubuntu 8.04 to set up the solution. Any Debian based distribution should propably work the same way provided there are reasonably new versions of OpenSSH available. It should also be quite simple to translate the instructions into any other *NIX flavour. I have access to two machines – one acting as the server and the other as the client. If you would like to try it out on a single machine first, it works equally well using virtual hosts.
1. Install OpenSSH Server
In Ubuntu, OpenSSH does not come installed by default, so the first step is to install the OpenSSH server from the repositories. On the server host, run the following command:
server$ sudo apt-get install openssh-server
2. Setup chroot jail for sftp
Next, we are going to restrict SFTP access to a certain directory that will act as a virtual root of the file system – much like what many are used with from regular FTP. Start with creating a user, bkuser, that will be used to access the server remotely:
server$ sudo adduser bkuser
You will be asked to enter a number of information about the user. Just follow the instructions, providing at least a password for the newly created user.
Next, we are going to modify the file /etc/ssh/sshd_config, so that users belonging to the sftpusers group will be restricted to a chrooted directory without access to the rest of the host file system:
server$ sudo nano /etc/ssh/sshd_config
include the following lines:
# Make sure you replace any existing 'Subsystem sftp' line with this
Subsystem sftp internal-sftp
# Add these lines at the end of sshd_config
# Put users in the sftpusers group in a chroot jail
Match Group sftpusers
ChrootDirectory %h
ForceCommand internal-sftp
AllowTcpForwarding no
This means that all users you add to the sftpusers group will be chrooted to their home directory, and will only be able to run the internal SFTP process.
In order for the changes to take effect, restart the ssh daemon:
server$ sudo /etc/init.d/ssh restart
* Restarting OpenBSD Secure Shell server sshd [ OK ]
Create a directory structure for the virtual SFTP server root:
server$ sudo mkdir /var/sftp
server$ sudo mkdir /var/sftp/.ssh
Create a new group for SFTP-only users. Membership of this group determines whether a user is chrooted or not:
server$ sudo groupadd sftpusers
Next, we will configure the SFTP users as follows:
- Assign them to the sftpusers group
- Deny any shell access by setting their shell to /bin/false
- Reassign their home directory to the desired chroot directory. This directory and any directories over it must be owned by root
For the user bkuser created earlier, start by assigning the user to the sftpusers group:
server$ sudo usermod -g sftpusers bkuser
Make sure the user does not have any shell access:
server$ sudo usermod -s /bin/false bkuser
Remove the old home directory and create a new directory for the user under the virtual root:
server$ sudo rm -r /home/bkuser
server$ sudo mkdir /var/sftp/bkuser
Make bkuser the owner of the bkuser subdirectory under the virtual root:
server$ sudo chown bkuser:bkuser /var/sftp/bkuser
Assign /var/sftp as the new home directory for bkuser:
server$ sudo usermod -d /var/sftp/ bkuser
3. Configure RSA key authentication
This section describes how to set up public key based authentication for the SFTP access. In order to do this, we need to head over to the client and start with creating the bkuser account here as well:
client$ sudo adduser bkuser
Follow the instructions to create the new user. Next, as the newly created user, we are going to ttpare an RSA keypair consisting of a private and public key:
client$ sudo su - bkuser
client$ mkdir ~/.ssh
client$ chmod 700 ~/.ssh
client$ ssh-keygen -q -f ~/.ssh/id_rsa -t rsa
When asked for a passphrase for the private key, we simply ttss enter in order to set a blank passphrase. This will allow us to connect later without being prompted for authentication.
Now, we need to copy the public key to server:
client$ sftp server
enter password to get to the sftp> prompt. Then:
sftp> cd bkuser
sftp> put .ssh/id_rsa.pub
Uploading .ssh/id_rsa.pub to /bkuser/id_rsa.pub
.ssh/id_rsa.pub 100% 395 0.4KB/s 00:00
sftp> exit
Now, we need set up the public key based authentication over at the server. Issue the following commands in order to copy the public key to the list of authorized keys that the SFTP server will accept for authentication:
server$ sudo -i
server$ cd /var/sftp
server$ cat bkuser/id_rsa.pub >> .ssh/authorized_keys
server$ rm bkuser/id_rsa.pub
server$ exit
Now, lets try it out, back on the client:
client$ sftp server
If successful, there should be no prompt for password…
4. Install sshfs file system and mount sftp to a local directory
In order to simplify file transfer, this step allows us to mount the SFTP directory locally, where it acts just as an ordinary directory even though the contents are pushed over the network to the SFTP server. The tool used for this purpose is SSHFS (SSH File System) which operates in user space, so there is no need for escalated privileges in order to mount the remote file system. First, install SSHFS by issuing the following command:
client$ sudo apt-get install sshfs
Next, we will su into bkuser and set up the local mount point:
client$ sudo su - bkuser
client$ mkdir mnt
client$ mkdir mnt/backup
And then, mount the remote SFTP file system to the newly created mount point:
client$ sshfs server:/bkuser ~/mnt/backup
Test to add/remove files in ~/mnt/backup, and when verified, unmount by issuing the fusermount command:
client$ fusermount -u ~/mnt/backup
5. Use rsync to perform backup
There are tons of guides available on how to use rsync, so this will be kept at a bare minimum. The goal here is just to simply create a backup copy of a single directory structure:
client$ sshfs server:/bkuser ~/mnt/backup
client$ rsync -a -v /path/to/files/ ~/mnt/backup/
client$ fusermount -u ~/mnt/backup
The above commands first mount the remote SFTP server, and then uses rsync in order to copy the contents in /path/to/files/ to the server. The flag -a stands for archive and is a convience flag that makes sure to ttserve ownership, time stamps and other attributes of the transferred files. Finally the file system is unmounted. After being unmounted, the ~/mnt/backup/ directory should be empty.
6. Combine it all into a scheduled backup
In order to work as a backup solution, it is convenient to set up the rsync operation as a scheduled task. In *NIX systems, the most straight forward way of doing this is by setting up a cron job. Cron schedules a single command, so in order to perform multiple operations, we need to set up a simple shell script that in turn gets called by the scheduler. First of all, we are going to create a directory for the scrip:
client$ mkdir ~/bin
Create a shell script called backup-files.sh in the ~/bin directory, for example with nano:
client$ nano ~/bin/backup-files.sh
Enter the following contents:
#!/bin/sh
sshfs server:/bkuser ~/mnt/backup
rsync -a -v /path/to/files/ ~/backup/
fusermount -u ~/backup
Make sure the script is runnable by setting the eXecutable flag:
client$ chmod +x ~/bin/backup-files.sh
In order to set up the scheduled task, we need to edit the crontab for bkuser:
client$ crontab -e
This will bring up an editor, where the following should be entered:
# m h dom mon dow command
0 3 * * * /home/bkuser/bin/backup-files.sh
The five first columns in the crontab specifies the schedule:
- Minute of hour
- Hour of day
- Day of month
- Month
- Day of week
The last column specifies the command to run when the scheduled time occurs. So for our case, the backup-files.sh command is called at 03:00 every day of the month, every month and every day of the week.
Thats it! You now have a simple but working, secure backup solution.

I’ve seen this guide for chrooted SFTP, and I’ve learnt from a lot of tutorials as this one. Here my compendium for optimal configuration in both clients and servers:
http://wiki.lapipaplena.org/index.php/How_to_mount_SFTP_accesses
(special care of users and permissions)