SFTP is file transfer over SSH, so it uses the same authentication as your shell login. Once an SSH key is installed on the server, sftp connects without a password, which makes uploads repeatable in scripts and cron jobs. This guide creates a key pair, installs the public key on your Linux VPS, and transfers files with SFTP using that key.
Before you start
You need:
- A Linux VPS you can already reach over SSH with a password or an existing key. Examples here use
203.0.113.10and the userdeploy. - An SSH client. OpenSSH is built into Linux, macOS and Windows 10/11 (
ssh,sftp,ssh-keygen,ssh-copy-id). PuTTY users should read Use SSH keys in PuTTY with Pageant instead. - Access to your VPS provider's control panel for the browser console and power controls, in case you lock yourself out.
Tip: If you have never connected before, start with Connect to your Linux VPS with SSH.
Step 1: Create an SSH key pair
Run this on your own computer, not on the server:
ssh-keygen -t ed25519 -C "deploy@laptop"Press Enter to accept the default path (~/.ssh/id_ed25519), then set a passphrase. A passphrase protects the private key if your laptop is stolen; you can load it once per session with ssh-agent (Step 6). You now have two files:
~/.ssh/id_ed25519— the private key. Never copy this to a server.~/.ssh/id_ed25519.pub— the public key. This is the one you install.
If a tool you rely on does not support Ed25519, create a 4096-bit RSA key instead:
ssh-keygen -t rsa -b 4096 -C "deploy@laptop"Step 2: Install the public key on the VPS
The fastest way is ssh-copy-id, which appends your public key to ~/.ssh/authorized_keys on the server and fixes the permissions:
ssh-copy-id -i ~/.ssh/id_ed25519.pub deploy@203.0.113.10Enter the account password one last time. If ssh-copy-id is not available, do it manually:
cat ~/.ssh/id_ed25519.pub | ssh deploy@203.0.113.10 \
"mkdir -p ~/.ssh && chmod 700 ~/.ssh && cat >> ~/.ssh/authorized_keys && chmod 600 ~/.ssh/authorized_keys"Permissions matter. SSH refuses to read authorized_keys if the directory or file is group- or world-writable.
Step 3: Confirm key login works
Test the key before you change any server setting:
ssh -i ~/.ssh/id_ed25519 deploy@203.0.113.10You should land in a shell without being asked for the account password. If you set a passphrase on the key, you will be asked for that instead.
Warning: Do not disable password authentication until key login is confirmed working in a second terminal. Keep your current session open while you test.
Step 4: Transfer files with SFTP using your SSH key
SFTP uses the same key automatically. Connect:
sftp deploy@203.0.113.10If the key is not in the default location, point at it explicitly:
sftp -i ~/.ssh/id_ed25519 deploy@203.0.113.10You get an sftp> prompt. The useful commands are:
pwdandlpwd— remote and local working directory.lsandlls— list remote and local files.cd /var/www/example.comandlcd ~/build— change remote and local directory.put app.tar.gz— upload a file. Add-rto upload a directory:put -r dist.get backup.sql— download a file.mkdir releases,rename old.txt new.txt,chmod 640 config.php,rm old.tar.gz.byeorexit— close the session.
A typical deploy session looks like this:
sftp> lcd ~/build
sftp> cd /var/www/example.com
sftp> put -r dist
sftp> chmod 644 index.html
sftp> byeStep 5: Automate transfers in batch mode
For scripts and cron jobs, feed SFTP a list of commands with -b. Use - to read from standard input, and BatchMode=yes so the client fails instead of prompting:
sftp -b - -o BatchMode=yes -i ~/.ssh/id_ed25519 deploy@203.0.113.10 <<'EOF'
lcd /home/deploy/backups
cd /home/deploy/incoming
put nightly.sql.gz
bye
EOFThe same works from a file:
sftp -b /home/deploy/sftp-upload.txt deploy@203.0.113.10Tip: For large trees where only changed files matter, rsync -avz -e ssh./dist/ deploy@203.0.113.10:/var/www/example.com/ reuses the same key and transfers less data. See Transfer files with SCP, SFTP, WinSCP or FileZilla.
Step 6: Make it convenient and safer
Load the key once per session so you are not retyping the passphrase:
eval "$(ssh-agent -s)"
ssh-add ~/.ssh/id_ed25519Save the host and key in ~/.ssh/config so plain sftp vps works:
Host vps
HostName 203.0.113.10
User deploy
IdentityFile ~/.ssh/id_ed25519
IdentitiesOnly yesIdentitiesOnly yes stops the agent from offering every key you own, which prevents the "Too many authentication failures" error. More shortcuts are in Use the SSH config file.
Once key login is proven, you can turn off password authentication on the server. Edit /etc/ssh/sshd_config:
PubkeyAuthentication yes
PasswordAuthentication noThen validate and reload:
sudo sshd -t && sudo systemctl reload sshWarning: Reloading with a broken config can lock you out. Keep an existing session open, and use your VPS provider's console if the reload fails. The full checklist is in Disable root login and password authentication over SSH.
Check it works
Run a verbose connection to see which key was accepted:
sftp -v -i ~/.ssh/id_ed25519 deploy@203.0.113.10Look for Offering public key followed by Server accepts key and Authentication succeeded (publickey). On the server, confirm the file and its permissions:
ls -ld ~/.ssh && ls -l ~/.ssh/authorized_keysYou want drwx------ on .ssh and -rw------- on authorized_keys. Then run one real transfer, for example put a small test file and check it with ls on the remote side.
Troubleshooting
Permission denied (publickey)— the server did not accept your key. Check that the public key is in~/.ssh/authorized_keysfor the right user, and that.sshis700andauthorized_keysis600. ConfirmAuthorizedKeysFilein/etc/ssh/sshd_configis not pointing elsewhere.Received disconnect... Too many authentication failures— your agent offered too many keys. Connect with-o IdentitiesOnly=yes -i ~/.ssh/id_ed25519, or addIdentitiesOnly yesto~/.ssh/config. See Fix SSH "Too many authentication failures".subsystem request for sftp failed— the SFTP subsystem is missing or commented out. Make sure/etc/ssh/sshd_configcontainsSubsystem sftp /usr/lib/openssh/sftp-server(orinternal-sftp), then reload SSH. On Ubuntu 24.04 and Debian 12 the line lives in/etc/ssh/sshd_config.d/too — check both.Host key verification failed— the server was rebuilt or its IP changed. Remove the stale entry withssh-keygen -R 203.0.113.10and reconnect.Connection refusedortimed out— the SSH port is blocked or the service is down. See Fix SSH connection refused, timed out and permission denied.
Next steps
- Create a locked-down account for uploads only: Create an SFTP-only user limited to one folder.
- Keep several keys for different machines: Manage several SSH keys for different servers.
- Block brute-force attempts on the SSH port: Protect SSH with Fail2ban.
