
If you manage Linux servers or simply have a computer with data that you can't afford to lose, learning to use rsync to automate backups It's practically mandatory. There's no need to set up an expensive suite or rely on proprietary tools: with a few well-thought-out commands, you can have a solid, efficient, and easy-to-maintain backup system.
Throughout this guide you will see From the basics of rsync to advanced editingLocal backups, remote backups via SSH, Time Machine-style backups with snapshots, production-ready scripts, cron, systemd timers, exclusions, rotations, and verification. See our Comparison of backup methods to decide on a strategy. The idea is that you finish the article with a clear plan and commands that you can practically copy and adapt to your environment.
What is rsync and why is it used so much for backups?
Rsync is a command-line tool designed for synchronize files and directories between two locations, either on the same computer or between different machines, usually via SSH or with its own rsyncd daemon.
The advantage of rsync over a simple cp or scp is that it implements a smart algorithm of differential block transferIt compares the source and destination and only sends the changes, not the entire file each time. If you have a lot of data and only modify small pieces, the time and bandwidth savings are enormous.
Additionally, rsync can preserve virtually all metadatapermissions, owners, groups, timestamps, symbolic links, devices… That's why it's so useful for "serious" backups, where not only the content matters, but also how the file system is set up.
Another important advantage is that rsync works both locally and remotelyYou can use it to synchronize two folders on the same server, to pull data from a remote server to your backup machine, or to push data to a remote NAS or VPS using SSH.

Install and test rsync on different distributions
Although many distributions already come with rsync installed, it's a good idea Verify the installation and update to a recent version. both on the source and destination machines before mounting your automatic backups.
On Debian or Ubuntu-based systems, you can do something as simple as:
rsync --version
sudo apt update
sudo apt install rsync
In distributions like RHEL, CentOS, Rocky Linux, or other derivatives, the procedure would be very similar, changing the package manager but with the same idea of ensure that rsync is available and up to date in both extremes.
rsync --version
sudo dnf install rsync # En sistemas modernos
sudo yum install rsync # En sistemas más antiguos
Basic rsync options you'll use all the time
Although rsync has a good arsenal of parameters, in practice for backups you'll spend 90% of your time using... a small set of options that should be memorized.
The overall structure of the command is quite straightforward, but there is one detail that adds a lot of possibilities: the trailing slash in the paths changes the behavior.
Generic syntax:
rsync ORIGEN DESTINO
The key difference lies in how you treat the source directory:
# Copia el directorio como tal dentro del destino
rsync -av /source/dir /backup/
# Copy ONLY the contents of the directory to the destination
rsync -av /source/dir/ /backup/
Some of the most commonly used backup options are especially practical because They combine many things in a short text.:
- -a: file mode. Equivalent to -rlptgoD (recursive, preserves symbolic links, permissions, timestamps, group, owner, and special files).
- -v: "Verbose" mode. Shows what it is doing and which files it is accessing.
- -z: compresses data during transfer, ideal for remote copies over the Internet.
- -h: makes sizes look "nice" (MB, GB…), perfect for humans.
- -P: combines progress and partial files, to see how things are going and be able to resume.
- –Delete: deletes at the destination the files that no longer exist at the source, leaving an exact replica.
- -n / –dry-run: simulates the execution without touching anything, fantastic for not messing things up.
- –exclude / –exclude-from: allows you to exclude patterns or a complete list of routes that you don't want to copy.
- –link-dest: creates hard links with a previous copy, the basis of Time Machine-type incremental backups.
Manual local copies and first examples
The first step before automating anything is to have clear and proven manual copy commandsLet's review typical cases that we will later use within scripts.
If you want to clone your home directory to a local backup diskThe minimal command would look like this:
rsync -av /home/usuario/ /mnt/disco_backup/usuario/
This rsync scans your home page complete preserving permissions, dates and structureand only copies what is missing or has changed since the last time, which is already a very neat incremental copy without complicating things.
Another classic example is synchronization project data, photos, or documents between two folders on the same server or even different disks, to have a second local game always fresh.
rsync -av /media/fotos/ /backup/fotos/
When it comes to sensitive system data, such as /etc or /var/wwwIt's normal to want a copy that's an exact mirror, removing from the backup what disappears in the original. That's where the famous deletion option comes in.
rsync -av --delete /var/www/ /backup/www/
Secure remote backups with SSH
Where rsync truly shines is when you combine it with SSH to send copies off the serverThis way, you can store your data on another node in your network, a NAS, or a VPS on the internet. This way, you're not dependent on a single device and you comply with part of the famous 3-2-1 rule (at least one off-site copy).
Ideally, you should configure public key authentication instead of manually entering passwords all the time. Once you have the key copied to the backup server, the commands become very intuitive.
# Empujar datos locales a un servidor remoto de backup
rsync -avz /etc/ backup@servidor-remoto:/backups/etc/
# Bringing data from a remote server to your backup machine
rsync -avz backup@remote-server:/var/www/ /backups/www/
In slightly more refined scenarios, you can adjust SSH encryption, port, or compression from rsync itself with -e, for example if your server is listening on a different port or you want to optimize a slow link.
rsync -avz \
-e "ssh -p 2222 -c -o Compression=no" \
/origen/ backup@servidor-remoto:/destino/
A useful trick when there are weak connections or shared networks is to use –bwlimit to avoid overloading the link and not leave anyone without internet while you launch a massive backup.
rsync -avz --bwlimit=5000 /datos/ backup@servidor-remoto:/backups/datos/
Full, differential, and incremental backups with rsync
Although rsync already performs differential transfers at the block level, from a backup strategy perspective it's worth considering three types of copies: full, differential, and incrementalwhich you can implement directly with rsync options.
A complete copy is straightforward: it recreates all the content of the source at the destination, ideal as initial backup or to have a clean reference.
# Copia completa de un árbol de directorios
rsync -a /ruta/origen/ /ruta/destino/
Differential copying builds on that foundation and focuses on keeping the destination aligned with the source, copying changes and removing what no longer exists. It's what you usually mean when you talk about... have a mirror of the system.
# Copia diferencial, manteniendo el destino idéntico al origen
rsync -a --delete /ruta/origen/ /ruta/destino/
The juiciest part is the "real" incremental backup, where in addition to synchronizing, You save histories by date without duplicating dataThis is where the –link-dest option comes into play, which creates hard links against a previous copy for files that have not changed.
# Copia incremental apoyada en una copia previa
rsync -a --link-dest=/ruta/a/copiaprevia \
/ruta/origen/ /ruta/destino-incremental/
With this approach, each backup folder appears to be a complete copy, but internally Identical files share blocks on diskThis greatly reduces the space used and allows for easy navigation through historical snapshots.
Time Machine style backups with snapshots and hard links
Many people want to replicate in Linux the convenience of macOS Time Machine with its snapshots by dateWith rsync it is perfectly possible by combining --link-dest, a little shell and some organization.
The idea is to maintain a current directory that points to the last good backup, and at the same time create folders with timestamp (date-time) that represent each snapshot. Unchanged files are linked with hard links to the previous snapshot, and new blocks are only written when there are actual differences.
A typical command in that scheme might be something like:
rsync -avPh --delete \
--link-dest="$TARGETDIR/current" \
"$SOURCEDIR/$USER/" \
"$TARGETDIR/$USER-$TIMESTAMP"
Then a script takes care of updating the symbolic link current so that it always points to the latest snapshotand to maintain a small history organized by date. With that, you can browse through older copies simply by entering the folder you're interested in.
Automation comes naturally: you save the script in something like /usr/local/bin/rsync-time-machine and schedule it to run daily with cron at the time that suits you best.
0 5 * * * bash /usr/local/bin/rsync-time-machine
Automate backups with cron on a daily basis
There comes a point where making copies by hand no longer makes sense; the normal thing to do is Schedule backups with cron so that they run automatically during off-peak hours (early morning, for example) and you can forget about them except to check the logs from time to time.
The process is always the same: you prepare a script that makes the complete copy with all the options (exclusions, logs, etc.), you give it execution permissions and you plug it into the crontab of the appropriate user or to root if it involves touching the entire system.
An example of a simple script for local copying could be:
#!/bin/bash
SOURCE_DIR="/home"
BACKUP_DIR="/backup/home"
LOG_FILE="/var/log/backup/rsync-local.log"
DATE=$(date +"%Y-%m-%d %H:%M:%S")
mkdir -p «$BACKUP_DIR» «$(dirname «$LOG_FILE»)»
echo "Local backup started" >> "$LOG_FILE"
rsync -av –delete
–exclude='*.tmp' \
–exclude='.cache' \
–exclude='Downloads/*' \
«$SOURCE_DIR/» «$BACKUP_DIR/» >> «$LOG_FILE» 2>&1
if ; then
echo » Backup completed successfully» >> «$LOG_FILE»
else
echo » Backup with errors» >> «$LOG_FILE»
fi
Once you have the script in, for example, /usr/local/bin/rsync-local-backup.sh And marked as executable, you add it to cron so that it runs at a specific time.
sudo chmod +x /usr/local/bin/rsync-local-backup.sh
sudo crontab -e
Inside crontab you could put something like:
0 2 * * * /usr/local/bin/rsync-local-backup.sh
systemd timers: a modern alternative to cron
In modern systems it is often worthwhile Use systemd timers instead of cronespecially if you want to better integrate services, manage network dependencies, or have centralized logs in journalctl.
The idea is to define a service that runs your backup script and a timer that indicates when to run it. The service could be something like:
Description=Rsync Backup Service
After=network-online.target
Wants=network-online.target
Type=oneshot
ExecStart=/usr/local/bin/rsync-remote-backup.sh
User=root
StandardOutput=journal
StandardError=journal
TimeoutSec=7200
WantedBy = multi-user.target
And the associated timer would be defined as follows, for a daily backup at 2 AM with some randomness so as not to overwhelm everything at once:
Description=Daily Rsync Backup Timer
Requires=rsync-backup.service
OnCalendar=*-*-* 02:00:00
Persistent=true
RandomizedDelaySec=10min
WantedBy=timers.target
With that, all that remains is to reload systemd, activate the timer, and verify that it programs correctly and that The service log shows that the copies are launched when it's time.
sudo systemctl daemon-reload
sudo systemctl enable --now rsync-backup.timer
systemctl list-timers
journalctl -u rsync-backup.service
Organize rotating backups: daily, weekly, and monthly
If you want something a bit more elaborate than a single static copy, you can set up a structure of rotating backups: daily, weekly, and monthlyusing hard links to save space and find to clean up old files.
A classic pattern involves having a current directory that is updated each time with rsync and then cloning that tree with hard links to daily, weekly and monthly folders depending on the day.
#!/bin/bash
SOURCE_DIR="/var/www"
BACKUP_ROOT="/backup/www"
CURRENT="$BACKUP_ROOT/current"
DAILY="$BACKUP_ROOT/daily"
WEEKLY="$BACKUP_ROOT/weekly"
MONTHLY="$BACKUP_ROOT/monthly"
DATE=$(date +%Y%m%d)
DOW=$(date +%u)
DOM=$(date +%d)
mkdir -p «$CURRENT» «$DAILY» «$WEEKLY» «$MONTHLY»
rsync -av –delete –link-dest=»$CURRENT» \
«$SOURCE_DIR/» «$CURRENT/»
&& cp -al «$CURRENT» «$DAILY/$DATE»
&& cp -al «$CURRENT» «$WEEKLY/$DATE»
&& cp -al «$CURRENT» «$MONTHLY/$DATE»
find «$DAILY» -maxdepth 1 -type d -mtime +7 -exec rm -rf {} \;
find «$WEEKLY» -maxdepth 1 -type d -mtime +28 -exec rm -rf {} \;
find «$MONTHLY» -maxdepth 1 -type d -mtime +365 -exec rm -rf {} \;
With this system you have a fairly reasonable historical window without filling the disk with full copies, and each snapshot remains navigable like a normal folder.
If your data changes quickly or is very large, you can adjust retention periods, frequencies, or even combine this with LVM or ZFS snapshots to ensure consistency of databases or virtual machines.
Monitor, verify, and find out if your backups are useful.
Having backup tasks running daily is great, but if no one checks the result It won't help you much. It's important to set up some basic monitoring to know if and when the last backup was made.
A simple tactic is to leave a small marker in the destination folder each time a backup completes successfully, for example, a .last-backup-success file with the date. Then, an external script, or even a Nagios/Icinga check, can alert you if that file is too old.
MARKER="/backup/www/.last-backup-success"
if ; then
echo "Marcador de backup no encontrado"
exit 1
fi
Another healthy habit is to check the Check rsync logs for errors or unusual transfer ratesA script that extracts statistics such as "Number of files", "Total size", "Speedup" and the like gives you a quick snapshot of how things are going.
And, of course, what really makes the difference is getting used to it every now and then. to do a real restorationTake a specific file, restore a version from yesterday or last week, and check that it opens correctly. This is the only way to be sure that, if everything goes wrong one day, your backups will be up to the task.
If you consolidate all these pieces—a well-configured rsync, automation with cron or systemd, sensible rotation, monitoring, and restore testing—you'll end up with a robust, flexible, and inexpensive Linux backup system, which takes full advantage of the benefits of free software without forcing you to give up convenience or reliability.
