Guides

Transfer files to a VPS: scp, rsync and SFTP from Windows, macOS and Linux

Copy files to and from your server with scp, sync folders with rsync over SSH, or drag and drop with WinSCP or FileZilla over SFTP. Exact commands inside.

Published ~10 min read

To copy files to a VPS, use scp for single files, rsync over SSH for folders and large or repeated transfers, and an SFTP client such as WinSCP, FileZilla or Cyberduck if you prefer drag and drop. All three run over the SSH connection you already use to log in, so nothing extra has to be opened on a Linux server. scp and sftp also work in the PowerShell of Windows 10 and 11.

the short version
# upload a file into your home directory on the server
scp site.zip user@203.0.113.10:/home/user/

# download a file into the current local folder
scp user@203.0.113.10:/var/log/nginx/access.log .

# upload a folder: only changed files are sent, and a broken transfer can resume
rsync -avz --partial --progress ./site/ user@203.0.113.10:/srv/site/

# interactive session with put, get, ls and cd
sftp user@203.0.113.10

Replace user with your login (often root on a fresh server) and the address with your server’s IP or hostname.

How do I use scp?

scp source target, where the remote side is written user@host:/path. The direction follows the order: local first uploads, remote first downloads.

scp
scp backup.tar.gz root@203.0.113.10:/root/                 # upload one file
scp file1.txt file2.txt root@203.0.113.10:/srv/data/       # several files
scp -r ./public root@203.0.113.10:/var/www/                # a folder, recursively
scp root@203.0.113.10:/etc/nginx/nginx.conf ./             # download
scp -P 2222 file.zip root@203.0.113.10:/root/              # SSH on another port: capital -P
scp -i ~/.ssh/id_ed25519 file.zip root@203.0.113.10:/root/ # a specific key
  • -P is a capital letter. ssh takes the port with -p, scp and sftp with -P; lowercase -p in scp means “preserve times and file modes”, so scp takes the port number for a file name.
  • Mind the colon. Without : after the host, scp makes a local copy named root@203.0.113.10 instead of uploading anything.
  • From Windows, the same commands work in PowerShell, because Windows 10, Windows 11 and recent Windows Server versions ship the OpenSSH client: scp C:\Users\me\Downloads\site.zip root@203.0.113.10:/root/. Your keys live in C:\Users\me\.ssh\.

Since OpenSSH 9.0, scp uses the SFTP protocol underneath instead of the old SCP protocol, and Debian 12, Ubuntu 24.04 and recent macOS releases ship such a client. You rarely notice, except against a server that has no SFTP: then add -O to use the legacy protocol, or turn SFTP on as shown in the errors below. Every other option, with an example each, is in the scp command reference.

How do I sync a folder with rsync?

rsync compares source and target and sends only what changed, so the second run of the same command takes seconds. It needs to be installed on both machines: sudo apt install rsync or sudo dnf install rsync.

rsync over SSH
# -a keeps permissions and times, -v lists files, -z compresses in transit
rsync -avz --progress ./site/ user@203.0.113.10:/srv/site/

# another SSH port or key
rsync -avz -e 'ssh -p 2222 -i ~/.ssh/id_ed25519' ./site/ user@203.0.113.10:/srv/site/

# leave things out
rsync -avz --exclude='.git' --exclude='node_modules' ./app/ user@203.0.113.10:/srv/app/

# download: the remote side comes first
rsync -avz user@203.0.113.10:/var/www/site/ ./site-backup/

What does the trailing slash do?

It decides whether rsync copies the folder or its contents, and it is the most common rsync surprise:

  • rsync -av site/ host:/srv/site/ copies the contents of site into /srv/site/.
  • rsync -av site host:/srv/site/ copies the folder itself and you end up with /srv/site/site/.

How do I make the target an exact mirror?

--delete removes files on the target that no longer exist in the source. Combined with a wrong slash or the wrong target path it deletes the wrong things, so always run it with --dry-run first and read the list:

mirror safely
rsync -avz --delete --dry-run ./site/ user@203.0.113.10:/srv/site/   # shows what would happen
rsync -avz --delete ./site/ user@203.0.113.10:/srv/site/             # then for real
Example output of the dry run
sending incremental file list
deleting old-page.html
about.html
index.html

sent 152 bytes  received 36 bytes  376.00 bytes/sec
total size is 17  speedup is 0.09 (DRY RUN)

Lines starting with deleting are files the real run will remove on the server; the others will be sent. Files that are already identical do not appear at all, and (DRY RUN) at the end confirms that nothing was changed.

Excludes, a non-standard SSH port, sudo on the far side, resumable transfers and --link-dest snapshot backups are in the rsync command guide.

Which program should I use for drag and drop?

Any client that speaks SFTP, the file transfer protocol built into SSH. Log in with the same user, port and key as for SSH; the server needs no FTP software.

  • WinSCP (Windows): New Site → File protocol SFTP, host, port 22 and user. For a key, go to Advanced → SSH → Authentication and pick the private key file; WinSCP offers to convert an OpenSSH key into its own .ppk format. Its Synchronize function covers what rsync does on the command line.
  • FileZilla (Windows, macOS, Linux): in the Site Manager, set Protocol to “SFTP – SSH File Transfer Protocol” and Logon Type to “Key file”, then choose your key. Download it from the official project site and decline any bundled extras the installer offers.
  • Cyberduck (macOS, Windows): Open Connection → “SFTP (SSH File Transfer Protocol)”, with your key in the SSH Private Key field.
  • Linux desktops: GNOME Files and Dolphin open sftp://user@203.0.113.10/ like a local folder.

How do I move one big file, or thousands of small ones?

For one large file, use rsync with --partial: if the connection drops, the same command picks up where it stopped instead of starting over. For a tree of many small files, pack it first, because one archive transfers much faster than ten thousand separate files:

large transfers
# resumable upload of one big file; just run it again after an interruption
rsync -P --append-verify bigfile.iso user@203.0.113.10:/srv/

# many small files: pack, copy, unpack
tar czf site.tar.gz ./site
scp site.tar.gz user@203.0.113.10:/srv/
ssh user@203.0.113.10 'tar xzf /srv/site.tar.gz -C /srv/'

# or in one go, without a temporary archive on either side
tar czf - ./site | ssh user@203.0.113.10 'tar xzf - -C /srv/'

# check that both copies are identical
sha256sum bigfile.iso && ssh user@203.0.113.10 sha256sum /srv/bigfile.iso

-P is short for --partial --progress. Packing and unpacking archives, and the flags that trip people up, are covered in the tar.gz guide.

Why does scp or rsync fail, and how do I fix it?

Permission denied (publickey)

The server refused your key before any file moved. Point the tool at the right key with -i (or -e 'ssh -i …' for rsync) and check that ssh alone can log in. If the key was never installed on the server, ssh-copy-id puts it there. The full checklist is in Permission denied (publickey).

scp: dest open …: Permission denied

A current scp (OpenSSH 9.0 or later) reports it as scp: dest open "/var/www/html/index.html": Permission denied, followed by scp: failed to upload file index.html to /var/www/html/. With -O or an older client the same problem reads scp: /var/www/html/index.html: Permission denied. Here the login worked, but your user may not write to the target directory. Either upload to your home directory and move the files with sudo, or give your user the directory:

on the server
# option 1: upload to ~ first, then move into place
sudo mv ~/index.html /var/www/html/
sudo chmod 644 /var/www/html/index.html      # readable for the web server

# option 2: let your user own the site directory
sudo chown -R "$USER":www-data /var/www/site

rsync can also run as root on the far end with --rsync-path="sudo rsync", provided your user may run sudo rsync without a password prompt.

REMOTE HOST IDENTIFICATION HAS CHANGED

The server’s host key differs from the one your computer saved, typically after a reinstall. Check that the change is expected, then remove the old entry; see Host key verification failed.

Connection timed out or Connection refused

Nothing to do with the copy itself: SSH cannot reach the server. A timeout points to a firewall, a wrong IP or a port that is filtered, see SSH connection timed out. “Refused” means nothing listens on that port, see SSH connection refused. The open port checker tells the two apart from outside your own network: No answer is the timeout case, Closed the refused one.

subsystem request failed on channel 0

Usually followed by scp: Connection closed, or a GUI client that refuses to connect. The SSH server has no SFTP subsystem configured, which newer scp and every SFTP client need. scp -O works around it; the fix is one line in /etc/ssh/sshd_config:

on the server · is there a Subsystem line?
grep -i '^Subsystem' /etc/ssh/sshd_config

If nothing is printed, add one of these lines to /etc/ssh/sshd_config:

/etc/ssh/sshd_config · one of these
# Debian, Ubuntu
Subsystem sftp /usr/lib/openssh/sftp-server
# Rocky Linux, AlmaLinux
Subsystem sftp /usr/libexec/openssh/sftp-server
# or, on any distribution
Subsystem sftp internal-sftp
apply
sudo sshd -t && sudo systemctl restart ssh    # the service is called sshd on Rocky and Alma

rsync: command not found / connection unexpectedly closed

rsync starts a second rsync on the server over SSH. If it is not installed there, you get bash: line 1: rsync: command not found (older bash versions leave out line 1:) followed by rsync: connection unexpectedly closed. Install rsync on the server.

Received message too long

An SFTP client shows this when your shell prints text during a non-interactive login, for example an echo in ~/.bashrc or /etc/bash.bashrc. The text lands in the middle of the SFTP protocol. Remove the output, or print it only in interactive shells: [ -t 1 ] && echo "Welcome".

How do I copy files to a Windows VPS?

A Windows server is reached over Remote Desktop, not SSH, so the easiest route is to share a local drive into the session:

  • Drive redirection: in Remote Desktop Connection (mstsc), open Show Options → Local Resources → More… and tick the drive. On the server it appears under This PC as “C on YOUR-PC”, and you copy files with Explorer. On a Mac, Microsoft’s Windows App offers the same under the connection’s folder settings.
  • Copy and paste of files through the clipboard also works for smaller files. If it does nothing, see RDP copy and paste not working.
  • Download on the server itself when the file is on the internet anyway: it is faster than routing it through your own connection.

For scripted transfers, run the OpenSSH server on Windows. On Windows Server 2019 and 2022 the first line installs it as an optional feature. Windows Server 2025 has it already, so start at the second line, or switch Remote SSH Access on under Local Server in Server Manager, which does the same. Afterwards scp, sftp and WinSCP connect to it as they would to a Linux server:

PowerShell (Administrator) on the Windows server
Add-WindowsCapability -Online -Name OpenSSH.Server~~~~0.0.1.0   # 2019 and 2022 only
Start-Service sshd
Set-Service -Name sshd -StartupType Automatic

Setup creates the firewall rule OpenSSH-Server-In-TCP, which opens port 22 to everyone. Limit it to your own address; replace YOUR_IP with the public IP of the computer you copy from:

PowerShell (Administrator) on the Windows server
Set-NetFirewallRule -Name OpenSSH-Server-In-TCP -RemoteAddress YOUR_IP
from your computer
scp .\report.xlsx Administrator@203.0.113.20:Desktop/

Moving a whole site to a new server?

Run rsync on the new server and pull from the old one, so the data travels directly between the two machines instead of through your home connection: rsync -avz olduser@old.example.com:/var/www/site/ /var/www/site/. The database goes across as a dump, and the order of the remaining steps (DNS, mail, certificates) is in moving from shared hosting to a VPS. Between two servers you run yourself, follow the server migration checklist. On a Standard KVM server with a Linux image, SSH is how you log in anyway, so scp and SFTP work from your first login, and rsync as soon as it is installed on both ends.

Frequently asked

Should I use scp or rsync?

Use scp for a quick copy of one or a few files. Use rsync for folders, for anything you copy more than once and for large transfers: it sends only what changed, can resume an interrupted transfer with --partial and can mirror a directory with --delete. rsync has to be installed on both machines, and Windows has no built-in rsync.

How do I copy a whole folder to a server?

With scp, add -r: 'scp -r ./site user@IP:/srv/'. With rsync, 'rsync -avz ./site/ user@IP:/srv/site/' copies the contents of site into /srv/site/; without the trailing slash after site, rsync creates /srv/site/site/. rsync is the better choice for repeated copies because it only sends changed files.

How do I resume an interrupted upload?

scp cannot resume; it starts over. With rsync, use -P (short for --partial --progress) and simply run the same command again after the interruption; for a single large file, --append-verify continues from where it stopped and checks the result. In an interactive sftp session, 'reput file' resumes an upload and 'reget file' a download.

How do I upload files to a Windows server?

The simplest way is drive redirection in Remote Desktop: in mstsc open Show Options, Local Resources, More, tick your drive, and copy files from This PC on the server. For scripted transfers, use the OpenSSH server: Windows Server 2025 has it installed, so you only start the sshd service, and on 2019 or 2022 you add it first with 'Add-WindowsCapability -Online -Name OpenSSH.Server~~~~0.0.1.0'. Then copy with scp or WinSCP.

Related articles

All guides