Rsync Files to a Server
Copy files to a server with rsync -avz /local/path/ user@host:/remote/path/. The trailing slash copies the folder's contents; leave it off and you get an extra nesting level. Run with -n first, use --delete only for a true mirror, and use an SSH key so cron can run it without a password.
For developers and server admins who deploy or back up websites over SSH and want repeatable rsync commands that do not wipe a live site.
knowledge
- Read time
- 5 min
- Sections
- 9
- Updated
- 14 Nov 2026
- Written by
- WebJi® team
Last editorial update: 14 November 2026.
What is the rsync command to copy files to a server?
Rsync sends only the parts of a file that changed, over SSH, which is why a second copy of a 2 GB site takes seconds. The whole syntax hangs on which side the remote host sits.
| Direction | Command | Use it for |
|---|---|---|
| Push | rsync -avz ./site/ user@203.0.113.10:/var/www/site/ | Laptop or build server to the live server |
| Pull | rsync -avz user@203.0.113.10:/var/www/site/ ./site-copy/ | Backup, or copying production down to test |
| Through a port | rsync -avz -e "ssh -p 2222" ./site/ user@host:/var/www/site/ | Any server that is not on port 22 |
The remote side needs rsync installed as well, even for a pull. On Debian or Ubuntu the package is rsync; on RHEL and its clones it is also rsync, from the base repository.
How does the trailing slash change what rsync copies?
This is the rule that catches everyone once. /var/www/site/ means the contents of that folder. /var/www/site means the folder itself.
rsync -av ./site/ host:/var/www/site/putsindex.phpat/var/www/site/index.php. Correct for a deploy.rsync -av ./site host:/var/www/site/puts it at/var/www/site/site/index.php. The site disappears behind a folder.- A trailing slash on the destination changes nothing. Only the source matters.
Which rsync flags matter on a web server?
-avz is the default most people type. Two of those three letters do real work, and one is often a waste.
| Flag | What it does | When to keep it |
|---|---|---|
-a | Runs recursively, keeping permissions, timestamps, links and ownership | Almost always, for a site deploy |
-z | Compresses during transfer | Slow or metered links. Drop it for JPEGs, video and zips, which are already compressed |
-P | Progress plus resumable partial files | Large uploads on a connection that drops |
--checksum | Compares content instead of size and mtime | Verifying a backup, not routine syncs |
--bwlimit=8000 | Caps transfer at about 8 MB/s | A daytime sync that must not saturate the link |
-e "ssh -p 2222" | Passes options to SSH | Non-standard port or a specific identity file |
How to exclude files from an rsync deploy
A raw copy of a project folder carries things the server does not need and should not serve: version history, build caches, logs and local environment files.
- Start with the obvious four:
--exclude='.git/' --exclude='node_modules/' --exclude='*.log' --exclude='.env' - Move the list into a file once it passes three entries:
--exclude-from=/etc/rsync-excludes.txt - Keep
.well-known/and any upload folder out of the exclude file. Both are needed on the live server. - Check the paths rsync actually sees with
-v. An unanchored pattern such ascache/matches a folder of that name at any depth, includingwp-content/cache/; start it with a slash,/cache/, to match only at the top of the source.
How to dry-run rsync and mirror safely with --delete
--delete removes anything on the server that is not in the source. That is what makes a mirror a mirror, and it is also how a wrong source path empties a live site. Never run it first.
- Dry run with the exact command you intend to use, plus
-n:rsync -avzn --delete ./site/ user@host:/var/www/site/ - Read the deletions in the output line by line. A wall of
deletinglines usually means a wrong source path or a missing trailing slash. - Take a server-side copy before the first real run:
ssh user@host "cp -a /var/www/site /var/www/site.bak" - Drop the
-nand run again. Keep-vfor the first run, then remove it.
If the site writes uploads or cache files on the server, exclude those folders instead of using --delete. A mirror will delete every file a visitor created since the last sync.
How to run rsync from cron with an SSH key
A sync that needs a typed password cannot run on a schedule. Generate a key for this job alone, copy the public half to the server, then test the login before you touch cron.
ssh-keygen -t ed25519 -f ~/.ssh/deploy_key -C "deploy"and leave the passphrase empty for a cron job, or load it into an agent. Key setup is covered step by step in generating an SSH key on Ubuntu.ssh-copy-id -i ~/.ssh/deploy_key.pub user@203.0.113.10- Add the host to
~/.ssh/configso the command stays short and cron does not parse quotes badly:Host live, thenHostName,User,PortandIdentityFile. - Write the job as a script with absolute paths:
/usr/bin/rsync -az --delete -e "ssh -i /home/deploy/.ssh/deploy_key" /var/www/build/ deploy@live:/var/www/site/ - Add the log redirect so a failure is visible:
0 2 * * * /usr/local/bin/deploy.sh >> /var/log/deploy.log 2>&1
How to fix file ownership after an rsync deploy
When rsync runs as root on the receiving server, -a also copies owner and group from the source, so files can land owned by a user the web server cannot read as. As a normal user, rsync cannot set ownership and the files belong to the receiving account instead. Either way, check permissions after the first deploy.
Set ownership to the web user after the transfer: chown -R www-data:www-data /var/www/site on Debian and Ubuntu, or the account user on a cPanel or DirectAdmin server. Files go to 644 and folders to 755, never 777. On a WordPress site the uploads folder usually needs to stay writable by the web user, which chown already handles.
If you sync as a non-root deploy user, add --no-o --no-g so rsync stops trying to set ownership it is not allowed to set. The transfer stops reporting errors, and the chown step becomes the only place ownership is set.
What do rsync exit codes 23 and 24 and other errors mean?
| Symptom | Cause | Fix |
|---|---|---|
| Exit code 23, "some files could not be transferred" | Usually a permission error, or a file that changed while being read | Read the list above the code, fix ownership, re-run. |
| Exit code 24, "some files vanished" | A file was deleted during the transfer, often a cache file | Re-run once. If it repeats every time, exclude that folder |
| Permission denied (publickey) | The key is not offered to the host, or ~/.ssh is 755 instead of 700 | Test with ssh -v host, fix the permissions, confirm the key is in authorized_keys |
| rsync: command not found | rsync is missing on the remote end, even for a pull | Install the package on both machines |
| Files transfer again on every run | Timestamps are not preserved on the destination filesystem | Add --checksum once to confirm, then fix the mount or use a filesystem that keeps mtime |
Where can you run rsync: shared hosting or a VPS?
Rsync over SSH needs a server where you have a shell account and a key of your own. A WebJi® VPS gives you root access from the first boot, so the deploy user, the key and the cron job are yours to create.
VPS configurations are quoted in INR by email at support@webji.services before you pay, with 18% GST shown on the invoice. If you are moving an account rather than a folder, the DirectAdmin restore guide covers archives and databases.
Sources: rsync(1) manual page (options, filter rules, exit values); OpenSSH ssh-keygen and ssh_config manuals.
Frequently asked questions
How do I copy files to a server with rsync?
Run rsync -avz /local/path/ user@server:/remote/path/. The local path comes first for a push. Put the remote host first to pull files down. The trailing slash on the source copies the folder's contents rather than the folder itself.
What does the trailing slash in rsync do?
It changes the source from the folder to its contents. With the slash, files land directly in the destination. Without it, rsync creates one more folder level, which is the usual reason a deploy shows an empty site.
Is rsync --delete safe?
Only after a dry run. Add -n to the exact command and read the deletion list before running it for real. Keep a server-side copy of the site, and never point --delete at a source path you have not checked.
How do I run rsync from cron without a password?
Use an SSH key with no passphrase, or load the key into an agent. Copy the public key with ssh-copy-id, use absolute paths inside the script, and redirect stdout and stderr to a log so a failed run is visible.
Why do files get 403 after an rsync deploy?
When the receiving rsync runs as root, -a copies the source owner and group, so the web server may not be able to read the files. Run chown -R www-data:www-data on the site folder, set files to 644 and folders to 755.
Can I use rsync on shared hosting?
Only if your host gives you SSH and rsync on the account. On shared hosting you usually deploy through the file manager, SFTP or git. Rsync needs a shell account, which is what a VPS or a dedicated server provides.
Last editorial update: 15 November 2026.
Ready to get started with WebJi®?
Join 12,000+ businesses across India and overseas. INR pricing, 18% GST shown before payment and 24/7 email support in Hindi and English — average first reply under 60 minutes.