Moving files to a server with plain FTP means sending usernames, passwords, and data across the network in clear text. SFTP fixes that, and if your Linux server already runs SSH, you’re most of the way to having it.
SFTP (SSH File Transfer Protocol) transfers files over an encrypted SSH connection. Despite the similar name, it isn’t FTP with security bolted on. It’s a separate protocol that runs on a single port (22), which makes it much easier to firewall than FTP.
This guide shows how to set up an SFTP server on Linux using OpenSSH, create a restricted user who can only access their own folder, and optionally lock it down with SSH keys. The commands use Ubuntu/Debian, with notes for RHEL-based systems where they differ.
Why Use SFTP Instead of FTP?
- Encrypted by default. Credentials and file contents are protected in transit.
- One port. Only port 22 needs to be open, with no passive port ranges to manage.
- Built on SSH. You get the same authentication options, including SSH keys.
- No extra server software. OpenSSH already includes an SFTP subsystem.
Step 1: Install and Enable OpenSSH
Most servers already have OpenSSH. If yours doesn’t, install it:
sudo apt update
sudo apt install openssh-server
On RHEL, Rocky, or AlmaLinux:
sudo dnf install openssh-server
Make sure the service is running and starts on boot (the service is called ssh on Ubuntu/Debian and sshd on RHEL-based systems):
sudo systemctl enable --now ssh
sudo systemctl status ssh
Step 2: Create a Group and a User for SFTP
Rather than configuring each user individually, create a group and apply the SFTP rules to everyone in it:
sudo groupadd sftpusers
Create a user with no shell access, so they can transfer files but can’t log in to a terminal:
sudo useradd -m -G sftpusers -s /usr/sbin/nologin sftpuser
sudo passwd sftpuser
The -s /usr/sbin/nologin option blocks interactive shell logins, while SFTP still works because it’s handled by the SSH daemon itself.
Step 3: Create the Chroot Directory Structure
A chroot “jail” confines the user to a specific directory so they can’t browse the rest of the filesystem. OpenSSH has a strict requirement here: the chroot directory and every parent directory must be owned by root and not writable by anyone else. The user can’t write to the jail root itself, so you create a writable subfolder inside it.
sudo mkdir -p /srv/sftp/sftpuser/uploads
sudo chown root:root /srv/sftp /srv/sftp/sftpuser
sudo chmod 755 /srv/sftp /srv/sftp/sftpuser
sudo chown sftpuser:sftpusers /srv/sftp/sftpuser/uploads
sudo chmod 755 /srv/sftp/sftpuser/uploads
When sftpuser connects, they land in their jail and see only an uploads folder, which is where they can read and write files.
Step 4: Configure the SSH Daemon
Open the SSH server configuration:
sudo nano /etc/ssh/sshd_config
Find the line that begins with Subsystem sftp and change it to use the internal SFTP server, which is required for chroot to work without copying binaries into the jail:
Subsystem sftp internal-sftp
Then add this block at the end of the file:
Match Group sftpusers
ChrootDirectory /srv/sftp/%u
ForceCommand internal-sftp
X11Forwarding no
AllowTcpForwarding no
What each line does:
Match Group sftpusersapplies the following settings only to members of that group.ChrootDirectory /srv/sftp/%ujails the user in a folder named after their username (%u).ForceCommand internal-sftpallows SFTP only and refuses any other command.X11Forwarding no/AllowTcpForwarding nodisable features an SFTP-only user doesn’t need.
Because a Match block applies until the next Match or end of file, always keep it at the bottom.
Step 5: Test the Configuration and Restart SSH
Check the file for syntax errors before restarting. A typo here could lock you out of the server:
sudo sshd -t
No output means the configuration is valid. Then restart the service:
sudo systemctl restart ssh
Keep your current SSH session open while you test from a second terminal, so you can fix any mistakes.
Step 6: Open the Firewall
If you use UFW and SSH is already allowed, nothing more is needed. Otherwise:
sudo ufw allow 22/tcp
On RHEL-based systems with firewalld:
sudo firewall-cmd --permanent --add-service=ssh
sudo firewall-cmd --reload
Step 7: Connect and Test
From another machine, connect with the command-line client:
sftp sftpuser@your-server-ip
Once connected, try a few commands:
sftp> pwd
Remote working directory: /
sftp> cd uploads
sftp> put report.pdf
sftp> ls
sftp> get report.pdf
sftp> exit
The jailed user sees / as their root, which is really /srv/sftp/sftpuser on the server. If you prefer a graphical client, FileZilla, WinSCP, and Cyberduck all support SFTP. Choose the SFTP protocol and port 22.
Optional: Use SSH Keys Instead of Passwords
Key-based authentication is more secure than passwords and avoids brute-force login attempts. On your client machine, generate a key pair:
ssh-keygen -t ed25519 -C "sftpuser"
Copy the public key to the server:
ssh-copy-id sftpuser@your-server-ip
ssh-copy-id needs password login to work the first time, and it writes to the user’s real home directory (/home/sftpuser/.ssh/authorized_keys), not the jail. That works fine, because sshd reads the key file before it applies the chroot.
Once key login works, you can disable passwords for the SFTP group by adding this line inside the Match Group sftpusers block:
PasswordAuthentication no
Run sudo sshd -t and restart SSH again.
Troubleshooting Common SFTP Issues
- “Broken pipe” or the connection closes right after login. This is almost always a chroot permissions problem. Verify that
/srv/sftpand/srv/sftp/sftpuserare owned byroot:rootand aren’t group- or world-writable. - “Permission denied” when uploading. The user can’t write to the jail root. Upload into the
uploadssubfolder instead, and confirm it’s owned by the user. - Login works but the user gets a shell prompt. The
Match Groupblock isn’t being applied. Check that the user is in the group (groups sftpuser), and that the block is at the end ofsshd_config. - Changes have no effect. Confirm you restarted the service and that
sshd -tpasses. Check the logs withsudo journalctl -u ssh -e(or/var/log/auth.logon Debian-based systems). - “Connection refused.” Check that the service is running and that the firewall allows port 22.
Security Tips
- Disable root login over SSH with
PermitRootLogin no. - Prefer SSH keys over passwords, and consider
fail2banto block repeated failed logins. - Give each user their own jail directory so they can’t see each other’s files.
- Keep OpenSSH updated with regular
apt upgradeordnf updateruns.
Conclusion
Setting up an SFTP server on Linux takes only a few minutes because OpenSSH already does the heavy lifting. Create a dedicated group and user, build a root-owned chroot directory with a writable subfolder, add a Match Group block to sshd_config, and restart the service. The result is an encrypted file transfer service that keeps each user confined to their own folder.
From there, add SSH keys, tighten your firewall rules, and monitor your logs, and you’ll have a file transfer setup that’s far safer than traditional FTP, with no extra software to maintain.
