Create SFTP-Only Backup Users on Ubuntu with chroot and SSH Keys

Updated on Nov 12, 2026
Kimberly N
6 MINS READ
Table of Contents
Create SFTP-Only Backup Users

Clients usually need a safe place to push backups. Giving them a normal SSH login is risky because a shell can reach far more than a backup folder. In this guide, you will learn to build SFTP-only backup users on Ubuntu: no shell, locked into one folder, and logged in with SSH keys only.

The steps below work on Ubuntu 22.04, 24.04, and 26.04 LTS. Run all server commands as a user with sudo.

Server Layout of This SFTP Backup Setup

Each of your SFTP-only backup users gets one account that can only use SFTP. The account is locked inside its own folder (a "chroot jail"), so it cannot see the rest of your server. Keys are stored outside the jail, so the client cannot change them. 

This least-privilege design fits client backups because it gives no shell access at all. The layout looks like this:

/srv/sftp/client1            <- chroot root (owned by root)/srv/sftp/client1/backups    <- writable folder (owned by client1)/etc/ssh/authorized_keys/client1   <- public key (owned by root)

Step 1: Create the Group and User

The first step is to create a group for all SFTP-only backup users, then add the first account with no shell. To do this, run the commands below:

Bash
sudo groupadd sftp-backupsudo mkdir -p /srv/sftp/client1/backupssudo useradd -d /srv/sftp/client1 -M -g sftp-backup -s /usr/sbin/nologin client1

The -M option stops Ubuntu from creating a home folder, and /usr/sbin/nologin blocks shell logins.

Step 2: Set the chroot Ownership Rules

This is the step that most people get wrong with SFTP-only backup users. SSH requires that the chroot folder and every parent folder above it are owned by root and not writable by anyone else. The user can only write in a sub-folder.

Set the ownership rules with the commands below:

Bash
sudo chown root:root /srv /srv/sftp /srv/sftp/client1sudo chmod 755 /srv /srv/sftp /srv/sftp/client1sudo chown client1:sftp-backup /srv/sftp/client1/backupssudo chmod 750 /srv/sftp/client1/backups

You can check the full path with the following command:

Bash
namei -l /srv/sftp/client1/backups

Every folder up to client1 must show root root and drwxr-xr-x.

Step 3: Create the SSH Key

Now use the command below to create the SSH keys. Run this on the client machine, the server that sends the backups, not on the VPS:

Bash
ssh-keygen -t ed25519 -f ~/.ssh/backup_client1 -C "client1-backup"cat ~/.ssh/backup_client1.pub

Use a passphrase if a person will use the key. For unattended jobs, use a key without one, and lock it down with the IP limit in the next step.

Step 4: Add the Key on the Server

It is recommended to store the public key for your SFTP-only backup users in a root-owned folder, outside the jail. This is safer than a ~/.ssh folder the user could reach.

Bash
sudo install -d -m 755 -o root -g root /etc/ssh/authorized_keyssudo nano /etc/ssh/authorized_keys/client1

Paste the key in one line. The restrict option turns off extras like port forwarding. The optional from= part allows only one source IP. Replace 203.0.113.10 with your client's IP:

restrict,from="203.0.113.10" ssh-ed25519 AAAAC3...yourkey... client1-backup

Set the file permissions with the following commands:

Bash
sudo chown root:root /etc/ssh/authorized_keys/client1sudo chmod 644 /etc/ssh/authorized_keys/client1

Step 5: Configure SSH for SFTP-Only Backup Users

Ubuntu loads extra files from /etc/ssh/sshd_config.d/, so you do not need to edit the main file. You can create a new one with:

Bash
sudo nano /etc/ssh/sshd_config.d/60-sftp-backup.conf
Match Group sftp-backup    ChrootDirectory /srv/sftp/%u    ForceCommand internal-sftp -d /backups -l INFO    AuthorizedKeysFile /etc/ssh/authorized_keys/%u    AuthenticationMethods publickey    PasswordAuthentication no    PermitTTY no    DisableForwarding yes
  • ChrootDirectory locks the user into /srv/sftp/<username>.
  • ForceCommand internal-sftp allows only SFTP. -d /backups opens the backups folder first, and -l INFO logs file actions.
  • AuthorizedKeysFile reads keys from the root-owned folder.
  • AuthenticationMethods publickey and PasswordAuthentication no allow keys only.
  • DisableForwarding yes turns off all forwarding, including X11 and agent forwarding.

Then, test the config and reload SSH. Keep your current session open until you confirm you can still log in:

Bash
sudo sshd -tsudo systemctl restart sshsudo sshd -T -C user=client1,host=localhost,addr=127.0.0.1 | grep -Ei 'chrootdirectory|forcecommand|authorizedkeysfile'

If you use AllowUsers or AllowGroups in your main config, add client1 or the sftp-backup group there too.

Step 6: Test Upload and Download

At this point, you must check that everything works. From the client machine, connect with the key:

Bash
sftp -i ~/.ssh/backup_client1 client1@YOUR_SERVER_IP

Inside the SFTP prompt, type the commands below:

sftp> pwdsftp> put test-backup.tar.gzsftp> ls -lsftp> get test-backup.tar.gz restored-test.tar.gzsftp> cd /sftp> ls

You should see only the backups folder at /. Now confirm that shell access is blocked:

Bash
ssh -i ~/.ssh/backup_client1 client1@YOUR_SERVER_IP

The server should reply that this service allows SFTP connections only, and then close the connection. This proves your SFTP-only backup users cannot get a shell.

Step 7: Check Logs and Fix Permission Errors

If something fails, the logs usually show why. Check them first, then use the table below to fix the most common permission errors.

Bash
sudo journalctl -u ssh -n 50 --no-pagersudo journalctl -t internal-sftp -n 50 --no-pager

If the log has no internal-sftp lines, check /var/log/auth.log as well. Here are the common problems:

Symptom Common cause Fix
Login works, then connection closes at once. Log says bad ownership or modes for chroot directory A folder in the chroot path is not owned by root, or is writable by group or others Re-run the chown and chmod commands in Step 2, then check with namei -l
Permission denied when uploading to / The jail root is read-only on purpose Upload to /backups
Permission denied inside /backups Wrong owner on the backups folder sudo chown client1:sftp-backup /srv/sftp/client1/backups
Permission denied (publickey) Wrong key, wrong file path, or wrong IP in from= Run ssh -vv on the client and check /etc/ssh/authorized_keys/client1
Connection closed for a user in AllowUsers setups User is missing from the allow list Add the user or group

Step 8: Rotate Keys and Check Backups

Rotate keys for SFTP-only backup users at least once a year, or at once when a person leaves. The safe way is to add the new key, test it, and then remove the old one:

Bash
sudo nano /etc/ssh/authorized_keys/client1

Put the new key line under the old one, test a login with the new key, then delete the old line. No SSH restart is needed, because SSH reads the key file on each login.

Also, check that backups are really arriving and are not damaged. Compare checksums on both sides:

Bash
sha256sum test-backup.tar.gzsha256sum /srv/sftp/client1/backups/test-backup.tar.gz

Run these checks on the server. The first one warns you if no new backup came in the last 24 hours. The other two show your disk space:

Bash
find /srv/sftp/client1/backups -type f -mtime -1 | grep -q . || echo "No new backup in 24h"df -h /srvdu -sh /srv/sftp/client1/backups

If your clients send very large backups, a dedicated server with large storage gives you the space and steady performance you need.

Note: SFTP-only accounts cannot run rsync over SSH, because that needs a shell. Use tools that speak SFTP, such as sftp or rclone.

Conclusion

At this point, you have SFTP-only backup users with no shell, a root-owned chroot jail, key-only login, logging, and an optional IP limit. The most important rule is the ownership of the chroot path, which root owns, and the user writes only in a sub-folder. Add one account per client, test each one, and rotate keys on a schedule. 

If you still need a server for this setup, a Linux VPS with root access is enough to run it.

No. ForceCommand internal-sftp allows only file transfers, and the shell is set to nologin.

SSH checks this before it enters the jail. If a normal user owned it, they could escape the jail.

No. internal-sftp runs inside SSH, so the jail needs no extra files.