Start typing to search across invoices, services, domains, tickets, and more...
Disk failure, an accidental rm or a ransomware attack can wipe data in seconds, so a reliable Linux server backup is non-negotiable. This guide combines four complementary methods: rsync to another server, tar archives on a cron schedule, rotated MySQL/MariaDB dumps and encrypted restic backups to S3-compatible storage, followed by restore tests. Commands work on Debian/Ubuntu and Rocky Linux/AlmaLinux.
rsync transfers only what changed, which makes it ideal for website directories and configuration. On the backup host create a regular user named backup and the directory /backup/web01; on the source server create a dedicated SSH key (see our SSH key tutorial). --delete removes files on the target that no longer exist on the source, so do a dry run with -n first.
# Install rsync on BOTH servers
apt install -y rsync # Debian / Ubuntu
dnf install -y rsync # Rocky Linux / AlmaLinux
# On the source server: dedicated key for backups
ssh-keygen -t ed25519 -f /root/.ssh/backup_key -N ""
ssh-copy-id -i /root/.ssh/backup_key.pub -p 22 [email protected]
# Preview first (-n = dry run), then run for real
rsync -aHn --delete -e "ssh -i /root/.ssh/backup_key -p 22" \
/etc /var/www [email protected]:/backup/web01/
rsync -aH --delete -e "ssh -i /root/.ssh/backup_key -p 22" \
/etc /var/www [email protected]:/backup/web01/
rsync creates a mirror: if you delete something on the source, the next sync deletes it on the backup too. Complement it with a dated tar archive every day and keep the last seven. The script prunes old archives with find -mtime, and cron runs it every night.
cat > /usr/local/bin/backup-files.sh <<'EOF'
#!/bin/bash
set -euo pipefail
DEST=/backup/files
KEEP_DAYS=7
mkdir -p "$DEST"
# tar exit code 1 = "file changed while reading", which is acceptable
tar -czpf "$DEST/files-$(date +%F).tar.gz" /etc /var/www /root || [ $? -eq 1 ]
find "$DEST" -name 'files-*.tar.gz' -mtime +$KEEP_DAYS -delete
EOF
chmod 700 /usr/local/bin/backup-files.sh
/usr/local/bin/backup-files.sh && ls -lh /backup/files
# Schedule: crontab -e
10 3 * * * /usr/local/bin/backup-files.sh >> /var/log/backup.log 2>&1
Copying the live database files often produces a corrupt backup; export with mysqldump or mariadb-dump instead. --single-transaction takes a consistent InnoDB snapshot without locking tables. The script dumps each database separately, compresses it with gzip and keeps 14 days. Credentials live in /root/.my.cnf with mode 600 so the password never appears on the command line or in the process list.
# Credentials (skip if root can log in to MariaDB/MySQL via unix_socket)
cat > /root/.my.cnf <<'EOF'
[client]
user=root
password=YourDatabaseRootPassword
EOF
chmod 600 /root/.my.cnf
cat > /usr/local/bin/backup-db.sh <<'EOF'
#!/bin/bash
set -euo pipefail
DEST=/backup/mysql
KEEP_DAYS=14
mkdir -p "$DEST"
CLIENT=$(command -v mariadb || command -v mysql)
DUMP=$(command -v mariadb-dump || command -v mysqldump)
for DB in $("$CLIENT" -N -e "SHOW DATABASES" | grep -Ev '^(information_schema|performance_schema|sys)$'); do
"$DUMP" --single-transaction --routines --triggers --events "$DB" \
| gzip > "$DEST/$DB-$(date +%F_%H%M).sql.gz"
done
find "$DEST" -name '*.sql.gz' -mtime +$KEEP_DAYS -delete
EOF
chmod 700 /usr/local/bin/backup-db.sh
# Schedule: crontab -e
20 2 * * * /usr/local/bin/backup-db.sh >> /var/log/backup.log 2>&1
restic offers deduplication, encryption and snapshots, and works with AWS S3, Cloudflare R2, MinIO and any other S3-compatible service. Include the database dump directory from Step 3 to get an off-site copy of everything. forget --prune applies a daily/weekly/monthly retention policy and frees space.
# Install restic
apt install -y restic # Debian / Ubuntu
dnf install -y epel-release && dnf install -y restic # Rocky / AlmaLinux
# Repository settings for an S3-compatible bucket
cat > /root/.restic.env <<'EOF'
export AWS_ACCESS_KEY_ID=YOUR_ACCESS_KEY
export AWS_SECRET_ACCESS_KEY=YOUR_SECRET_KEY
export RESTIC_REPOSITORY=s3:https://s3.example.com/my-backup-bucket/web01
export RESTIC_PASSWORD_FILE=/root/.restic.pass
EOF
openssl rand -base64 32 > /root/.restic.pass
chmod 600 /root/.restic.env /root/.restic.pass
. /root/.restic.env
restic init
restic backup /etc /var/www /backup/mysql
restic forget --keep-daily 7 --keep-weekly 4 --keep-monthly 6 --prune
restic snapshots
# Schedule: crontab -e
40 3 * * * { . /root/.restic.env && restic backup -q /etc /var/www /backup/mysql && restic forget -q --keep-daily 7 --keep-weekly 4 --keep-monthly 6 --prune; } >> /var/log/restic.log 2>&1
/root/.restic.pass and the S3 keys somewhere safe, such as a password manager, not only on the server being backed up.A backup that has never been restored is only a hope. Run a restore drill at least monthly: extract files into a temporary folder, import a dump into a test database and compare row counts, and run restic check. Ideally rebuild onto a fresh server once and note how long it takes.
# Files: list an archive and extract one directory to a temp folder
tar -tzf /backup/files/files-2026-10-01.tar.gz | head
mkdir -p /tmp/restore
tar -xzf /backup/files/files-2026-10-01.tar.gz -C /tmp/restore etc/nginx
# Database: import into a throw-away database and compare
mysql -e "CREATE DATABASE restore_test"
gunzip -c /backup/mysql/shop-2026-10-01_0220.sql.gz | mysql restore_test
mysql -e "SELECT COUNT(*) FROM restore_test.orders"
mysql -e "DROP DATABASE restore_test"
# restic: verify the repository and restore the latest snapshot
. /root/.restic.env
restic check
restic restore latest --target /tmp/restic-restore --include /etc/nginx
Lower KEEP_DAYS, exclude caches and logs (--exclude with tar) and move backups to another server or object storage. See our disk-space-full tutorial for cleanup tips.
Check /var/log/backup.log and journalctl -u cron (crond on Rocky). Cron has a minimal PATH, so use full paths in scripts and make sure the script is executable.
With InnoDB and --single-transaction tables are not locked, but the dump still uses disk I/O, so schedule it off-peak. For very large databases consider physical hot backups with mariadb-backup or Percona XtraBackup.
Still stuck after following these steps? Open a support ticket and the IMIDC 24/7 technical team will help. Include the server IP, OS version, the commands you ran and the full error output so we can pinpoint the issue faster.