riksi Start a project

Trick 02 Tricks & hacksTerminal

How to copy a remote folder to your computer with rsync

Updated 4 min read By

You need a copy of a folder from a server, and you don’t want to download all of it again next time. To copy a folder from a server to your computer, run rsync -avz user@server:/path/to/folder/ ./folder/. rsync connects over SSH and copies everything the first time. On later runs, it only sends the files and parts of files that have changed.

rsync -avzP [email protected]:/var/www/site/wp-content/uploads/ ./uploads/

So it’s good for pulling a site’s uploads folder down to a local copy. It also suits a quick backup, or refreshing a staging folder without downloading gigabytes you already have.

What each option does

Option What it does
-a Archive mode. Copies folders recursively and keeps symlinks, permissions and modification times. It already includes -r, so -ar is not needed.
-v Lists each file as it is transferred.
-z Compresses data in transit. It helps with text files like SQL dumps, CSS and logs. It does little for images and zip files.
-P Short for --partial --progress. Shows progress for each file and keeps partly transferred files, so an interrupted copy can resume.
-n Dry run. Shows what would be transferred without changing anything.

I’d use -avzP for most jobs. You can see the progress, and a dropped connection doesn’t mean starting again.

The user@host:/path form, with a single colon, means “connect over SSH”. A double colon (host::module) means something else. It connects to an rsync daemon, a separate service that most web servers don’t run. If you see :: together with -e ssh in an old snippet, it’s a mistake. One colon too many, and rsync goes looking for a service that isn’t there.

The trailing slash rule

A slash at the end of the source path changes what gets copied.

# Copies the contents of uploads into ./backup/
rsync -av server:/var/www/uploads/ ./backup/
# result: ./backup/2026/...

# Copies the uploads folder itself into ./backup/
rsync -av server:/var/www/uploads ./backup/
# result: ./backup/uploads/2026/...

I read the trailing slash as “the contents of”. Without it, rsync copies the box. With it, rsync copies what’s in the box. A slash on the destination makes no difference. So when you want the two folders to match, end both paths with a slash.

Always do a dry run first

Add -n (or --dry-run) to see exactly what would happen. Add -i (--itemize-changes) as well, and it also tells you why each file would be sent:

rsync -avzni [email protected]:/var/www/site/ ./site/

Yes, that means running the command twice. The first run only looks and never changes a file. This matters most with --delete. That option removes files from the destination that no longer exist in the source, so the two folders match exactly. It’s useful for a true mirror, but dangerous if you swap the source and destination. An upload with --delete in the wrong direction deletes files on the live server. My advice is to run it with -n first, read the list, then run it for real.

Custom SSH ports, keys and exclusions

For a non-standard SSH port or a specific key, pass SSH options with -e.

rsync -avzP -e 'ssh -p 2222 -i ~/.ssh/id_ed25519' [email protected]:/var/www/site/ ./site/

Skip folders you don’t need with --exclude. Patterns are matched relative to the source folder. A trailing slash matches folders only. Slashes matter here too. rsync reads every one of them.

rsync -avzP --exclude='cache/' --exclude='node_modules/' --exclude='*.log' \
  [email protected]:/var/www/site/ ./site/

For a longer list, put one pattern per line in a file and use --exclude-from=.rsync-exclude.

If you connect to the same server often, I’d add an entry to ~/.ssh/config. It keeps the command short, and it works for ssh, scp and rsync:

Host staging
  HostName staging.example.com
  User deploy
  Port 2222
  IdentityFile ~/.ssh/id_ed25519

Then use the short name in the command.

rsync -avzP staging:/var/www/site/wp-content/uploads/ ./uploads/

Uploading works the same way

To push files to the server, swap the order so the local folder comes first. For example, rsync -avzP ./dist/ staging:/var/www/site/. The source is always the first path. Check it twice before you add --delete.

rsync on a Mac and on the server

rsync has to be installed at both ends. Most Linux servers have it, but some shared hosts don’t. For an occasional copy there, scp -r or SFTP will do.

On macOS, check what you have with rsync --version. From macOS Sequoia 15.4, /usr/bin/rsync is Apple’s openrsync, which supports only some of rsync’s options. Before that, Apple shipped rsync 2.6.9 from 2006.

The everyday flags in this post work with both. Newer options need the current version. One example is --info=progress2, which shows one overall progress bar instead of one per file. Install it with brew install rsync. Then make sure Homebrew’s folder comes first in your PATH, the list of folders your shell searches for commands.

For most jobs, the first command in this post is all you need. I’d add -n whenever you’re not sure what will happen, and always before --delete. After that, let rsync do the dull part. It never gets tired of comparing files.

Filed under Tricks & hacksTerminal
Tagged
Share:

Comments

No comments yet. Questions, fixes and better ways are all welcome.

Leave a comment

Your email is never shown. Comments are checked before they appear, so yours may take a little while.

Start a project

Tell us what is
not working.

A few lines is enough. A real person reads every message and replies by email. Or choose the way that suits you.