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:
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:
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:
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:
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.
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:
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:
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:
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:
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:
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.
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:
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:
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:
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.