How to use rsync over SSH

Run rsync -avz src/ user@server:/srv/app/. rsync uses SSH by default and sends only what changed. It has to be installed on both machines. The slash after src/ means the contents of the folder, and without it you get /srv/app/src/. For another port add -e "ssh -p 2222". Before you use --delete, run the same command with --dry-run.

Updated . rsync 3.5.0 on Debian 13 between two throwaway containers.

The command to start from

rsync -avz src/ user@server:/srv/app/
  • -a copies folders and keeps permissions, times and links.
  • -v lists the files it transfers.
  • -z compresses during the transfer, which helps with text on a slow link and adds little for files that are already compressed.

Run it twice in a row and the second run lists no files. Change one file and it lists only that file.

To pick between the three tools, see scp vs SFTP vs rsync.

The trailing slash

A slash at the end of the source changes the result. With a folder called site:

CommandResult on the server
rsync -a site server:www/www/site/index.html
rsync -a site/ server:www/www/index.html

A slash at the end of the destination makes no difference to this.

Custom port or key

rsync -avz -e "ssh -p 2222" src/ user@server:/srv/app/
rsync -avz -e "ssh -i ~/.ssh/id_work" src/ user@server:/srv/app/

A Host entry in your SSH config also works and is shorter: rsync -avz src/ server:/srv/app/.

Large files: progress and resume

rsync -aP big.bin user@server:/tmp/

-P means --partial --progress. Without --partial, rsync removes a file it did not finish. With it, the partial file stays and the next run uses it. We stopped a 30 MB transfer partway. Without --partial no file remained on the server. With it, about 4 MB remained, the same rsync -aP finished the job, and the checksums of both copies matched.

--dry-run and --delete

--delete removes files on the destination that are not in the source. Always preview with --dry-run, or -n:

$ rsync -avn --delete site/ server:www2/
sending incremental file list
deleting oldfile
...
total size is 9  speedup is 0.05 (DRY RUN)

The file is still there after this. Remove -n to do it for real.

Three ways --delete hurts

  • An empty source empties the destination. A dry run with an empty empty/ folder as the source planned to delete everything in the target. If a mount failed and the source folder is empty, that is what you get.
  • A wrong slash deletes more than you meant. The destination is compared with the source as you wrote it, so with site against www/, anything else in www/ gets deleted.
  • Excludes interact with it. Excluded files are left alone unless you add --delete-excluded. In our test that removed debug.log from the server.

A limit stops a run that would delete too much. It exits with code 25:

$ rsync -a --delete --max-delete=1 empty/ server:www2/
Deletions stopped due to --max-delete limit (2 skipped)

Other useful forms

TaskCommand
Downloadrsync -av server:www/ back/
Skip filesrsync -av --exclude='*.log' site/ server:www/
See what would change and whyrsync -ain site/ server:www/
Create missing folders on the targetrsync -a --mkpath site/ server:a/b/c/

Without --mkpath, a target more than one folder deep fails with mkdir ... failed: No such file or directory.

Errors

If rsync is not installed on the server, you get messages like these, and the fix is to install it there:

rsync: connection unexpectedly closed (0 bytes received so far) [sender]
rsync error: remote command not found (code 127)

A source folder that does not exist gives change_dir ... failed: No such file or directory and exit code 23.

On a Mac

rsync on the Mac we used is openrsync, which reports rsync version 2.6.9 compatible. It handled the basic options above, but its help has no --mkpath or --append-verify. If you need those, install a newer rsync with Homebrew.

Questions

Does rsync over SSH need rsync on the server?

Yes. rsync runs on both ends. Without it on the server you get remote command not found (code 127).

How do I use rsync with a different SSH port?

Pass the SSH command with -e, for example rsync -avz -e "ssh -p 2222" src/ user@server:/srv/app/, or set the port in a Host entry of ~/.ssh/config.

What does the trailing slash mean in rsync?

On the source, src/ copies the contents of the folder and src copies the folder itself. On the destination it makes no difference.

Sources

More in SFTP and file transfer

All guides