I have used Linux for decades and done some fairly technical things with it, yet somehow I never used rsync. For years I backed up my websites to an external drive with cp -R, which copies every file, every time. One of my sites is 22 GB, with feature-length documentaries in it, so each backup was a long wait for nothing: almost all of those files hadn’t changed since the last backup.
rsync fixes that. The first run copies everything. Every run after that copies only what is new or changed, so a backup where only a few pages were edited can finish in seconds.
Here is a basic, first command I just used:
rsync -av /usr/local/apache2/weird /media/guy/44789107-bc7f-4a47-83bb-575839fe5d6e/Storage/SingleSites
How rsync decides what to copy
A common misunderstanding (I had it too) is that rsync simply skips files that already exist at the destination. That is not quite right. By default, rsync compares each file’s size and modification time on both sides:
- If both match, the file is skipped.
- If either differs, for example you edited a page or replaced a video, rsync copies the new version over the old one.
- If the file doesn’t exist at the destination, it is copied.
That is exactly what you want for backups: unchanged files are skipped, but changed files still get updated.
rsync keeps no records. There is no database, JSON file, or log of what was copied last time. Every run compares the source and destination directly, file by file, as they exist at that moment. It doesn’t matter how the files got onto the backup drive.
If you really do want “skip anything that already exists, even if it changed,” that is a separate option, --ignore-existing. It’s rarely the right choice for backups.
The basic command
rsync -av /var/www/ufo_site/ /media/external/ufo_site/
-a(archive) recurses into subdirectories and preserves permissions, timestamps, symlinks, and ownership. Preserving timestamps is what lets future runs recognize unchanged files.-v(verbose) lists each file as it is copied.
The trailing slash matters
This is the most common rsync mistake, so it’s worth memorizing:
/var/www/ufo_site/with a slash copies the contents of the folder into the destination./var/www/ufo_sitewithout a slash copies the folder itself, creatingufo_siteinside the destination.
So these two commands produce the same result:
rsync -av /var/www/ufo_site/ /media/external/ufo_site/
rsync -av /var/www/ufo_site /media/external/
Mixing the styles up is how you end up with /media/external/ufo_site/ufo_site/ and a second full copy eating your drive.
Useful options
| Option | What it does |
|---|---|
-n or --dry-run |
Shows what would be copied without copying anything. Use it the first time you run any new rsync command. |
--progress |
Shows a progress bar for each file. Handy for large video files. |
--delete |
Removes files from the backup that you’ve deleted from the source, keeping an exact mirror. Be careful: pointed at the wrong directory, it will delete things. Always do a dry run first. |
--ignore-existing |
Skips any file that already exists at the destination, even if the source version changed. |
--size-only |
Compares by size only, ignoring modification times. Useful for a one-time cleanup run (see “Already have an old cp backup?” below). |
--modify-window=2 |
Treats timestamps within 2 seconds as equal. Needed for FAT32/exFAT drives. |
--partial |
Keeps partially copied files if a transfer is interrupted, so a huge file doesn’t have to restart from zero. |
A good everyday backup command with a progress display:
rsync -av --progress /var/www/ufo_site/ /media/external/ufo_site/
It depends on how your backup drive is formatted
The filesystem on your external drive changes which command works best.
ext4 (Linux native)
Everything is preserved: permissions, ownership, timestamps. Use -av as-is.
rsync -av --progress /var/www/ufo_site/ /media/external/ufo_site/
The downside is that Windows can’t read ext4 without extra software.
NTFS (Windows native)
NTFS works well with rsync, with one limitation.
- Timestamps are fine. NTFS stores modification times very precisely, so rsync can tell which files are unchanged. No
--modify-windowneeded. - Permissions and ownership are not preserved. Linux mounts NTFS through the
ntfs-3gorntfs3driver, which by default shows every file with the same owner and permissions, usually whoever mounted the drive. rsync’s-atries to set permissions and ownership on each file, and the driver usually ignores that silently.
If you see errors like Operation not permitted, drop the permission and ownership parts of -a:
rsync -rltv --progress /var/www/ufo_site/ /media/external/ufo_site/
Here -r recurses, -l copies symlinks as symlinks, -t keeps timestamps, and -v is verbose. That’s -a minus permissions, owner, group, and device files.
FAT32 and exFAT
- Like NTFS, they can’t store Linux permissions or ownership, so use
-rltvinstead of-av. (FAT32 and exFAT don’t support symlinks either; rsync will report those as skipped.) - Their timestamps are less precise (FAT32 rounds to 2 seconds), which can make rsync think files changed when they didn’t and recopy them every time. Add
--modify-window=2to fix that. - FAT32 cannot store any file larger than 4 GB. That rules it out for full-length video files. exFAT does not have this limit.
rsync -rltv --modify-window=2 --progress /var/www/ufo_site/ /media/external/ufo_site/
Quick comparison
| Drive format | Recommended flags | Notes |
|---|---|---|
| ext4 | -av |
Preserves everything. Not readable by Windows. |
| NTFS | -av, or -rltv if you get permission errors |
Timestamps fine; permissions and ownership not kept. |
| exFAT | -rltv --modify-window=2 |
No permissions or symlinks. No file size limit. |
| FAT32 | -rltv --modify-window=2 |
No permissions or symlinks. 4 GB maximum file size. |
Restoring from an NTFS or FAT drive
Because permissions and ownership aren’t stored, a restored site needs them reset. That’s quick work, typically something like:
sudo chown -R www-data:www-data /var/www/ufo_site
sudo find /var/www/ufo_site -type d -exec chmod 755 {} \;
sudo find /var/www/ufo_site -type f -exec chmod 644 {} \;
Adjust the user, group, and modes to match your own server setup. If you ever want permissions preserved exactly on a non-Linux drive, put the permission-sensitive parts (config files, scripts) into a tar archive, which records permissions inside the archive itself. Big video files don’t care about permissions, so plain rsync is fine for those.
cp vs. rsync: who preserves timestamps?
Both can, but only when you ask them to.
rsync -ralone does not preserve modification times.-tdoes, and-aincludes-t.cp -Ralone does not preserve modification times. Every copy gets the time you ran the command.cp -ppreserves timestamps, permissions, and ownership.cp -a(archive mode) does what-pdoes, plus recursion and symlinks.
This matters because rsync uses modification times to decide what to skip.
Already have an old cp backup?
Say you once backed up a site like this:
cp -R -f -v weird_site /media/guy/4489M/
rsync will still work against that copy, since it keeps no records and just compares what’s there. But because plain cp -R gave every copied file a new timestamp, rsync’s default size-and-time check will see every file as different and recopy everything on the first run. It works, it just doesn’t save you anything that first time.
You have two choices.
Option 1: Just start fresh. Delete the old cp copy (or point rsync at the same folder and accept one full copy). From then on, rsync handles it. This is the simplest choice if you don’t have a lot of data.
Option 2: Fix it with one size-only run.
rsync -rltv --size-only weird_site/ /media/guy/4489M/weird_site/
This skips any file whose size matches, which will be nearly all of them. Because -t is included, rsync also corrects the timestamps on the skipped files to match the source. After this single run, drop --size-only and use the normal command. The one trade-off: during that first run, a file that changed but stayed exactly the same size would be missed. That’s rare.
Either way, watch your paths. Since that cp command created /media/guy/4489M/weird_site, the rsync destination must be that same folder, with weird_site/ (trailing slash) as the source. Otherwise you’ll end up with a second copy somewhere else.
Bonus: things rsync does that cp can’t
- Backups over the network. rsync works over SSH with no extra setup:
rsync -av /var/www/ufo_site/ user@otherbox:/backups/ufo_site/ - Resuming interrupted copies. If a big backup gets cut off, just run the same command again. Completed files are skipped and it picks up where it left off. Add
--partialso a half-copied large file doesn’t restart from the beginning.
Bonus: readable dates in database backup filenames
For database dumps, a dated filename makes backups easy to identify. This:
mysqldump invision > `date +%m_%d_%Y_%H%M%S`_INVISION_FORUM.sql
produces cluttered names like 02_10_2026_143522_INVISION_FORUM.sql. Dropping the time gives something cleaner:
mysqldump invision > $(date +%m_%d_%Y)_INVISION_FORUM.sql
Result: 02_10_2026_INVISION_FORUM.sql. The $(...) form does the same thing as backticks but is easier to read and nest.
- Running more than once a day? Each run overwrites that day’s file. Keep hours and minutes with
$(date +%m_%d_%Y_%H%M), which gives02_10_2026_1430_INVISION_FORUM.sql. - Want them to sort in order? Put the year first with
$(date +%Y_%m_%d), which gives2026_02_10_INVISION_FORUM.sql. With year-first names,lslists backups chronologically. With month-first names, January 2027 sorts before February 2026.
Keep the password off the command line
Writing --password=... in a command exposes it to other users through ps and saves it in your shell history. Store the credentials in ~/.my.cnf instead:
[mysqldump]
user=your_db_user
password=your_db_password
Lock the file down so only you can read it:
chmod 600 ~/.my.cnf
Now the command needs no credentials at all:
mysqldump invision > $(date +%Y_%m_%d)_INVISION_FORUM.sql
Cheat sheet
# Preview first (dry run)
rsync -avn /var/www/site/ /media/external/site/
# Backup to an ext4 or NTFS drive
rsync -av --progress /var/www/site/ /media/external/site/
# NTFS drive giving permission errors
rsync -rltv --progress /var/www/site/ /media/external/site/
# FAT32 / exFAT drive
rsync -rltv --modify-window=2 --progress /var/www/site/ /media/external/site/
# Exact mirror (also removes files deleted from the source) - dry run first!
rsync -av --delete /var/www/site/ /media/external/site/
# One-time fix for an old cp backup without timestamps
rsync -rltv --size-only /var/www/site/ /media/external/site/
# Backup to another machine over SSH
rsync -av /var/www/site/ user@otherbox:/backups/site/
# Dated database dump
mysqldump dbname > $(date +%Y_%m_%d)_DBNAME.sql
Remember: trailing slash on the source means “copy the contents.” No slash means “copy the folder itself.”