Kokil Thapa - Professional Web Developer in Nepal
Freelancer Web Developer in Nepal with 15+ Years of Experience

Kokil Thapa is an experienced full-stack web developer focused on building fast, secure, and scalable web applications. He helps businesses and individuals create SEO-friendly, user-focused digital platforms designed for long-term growth.

Automated Server Backups Complete Setup

By Kokil Thapa | Last reviewed: September 2026

You lose data the day you skip backups, not the day a disk fails. An automated server backups complete setup turns nightly dumps, file sync, and off-site copies into a routine you never have to remember. I run this pattern on Ubuntu servers that host Laravel and WordPress production stacks, including sister sites on a shared Deployer 7 pipeline. This guide walks through a copy-paste workflow: what to back up, how to schedule it, where to store copies, and how to prove a restore works before you need one.

What should an automated server backups complete setup include?

Think in layers. You need local hot copies for fast rollback, off-site warm copies for server loss, and a written restore path anyone on the team can follow.

A complete stack covers four asset classes on a typical PHP web server:

  • Databases — MySQL 9.7 or MariaDB 12.3 dumps for Laravel, WordPress, and custom apps
  • Application files — code, .env, uploaded media, and shared storage outside Git
  • Server config — Nginx or Apache vhosts, PHP-FPM pools, SSL paths, cron entries
  • Secrets inventory — a checklist of what lives only on disk, not in your password manager

On legal-tech portals and booking systems I maintain, uploaded PDFs and client documents often matter more than the database row count. Back up storage/app and any custom upload roots explicitly.

Backup Layer ArchitectureProductionApp + DB + uploadsLocal Archive/var/backups dailyOff-Site CopyS3 or remote VPSRetention Policy7 daily, 4 weekly, 6 monthlyRestore TestMonthly drill to staging3-2-1 rule: 3 copies, 2 media types, 1 off-site
Automated server backups complete setup uses local archives, off-site sync, retention tiers, and scheduled restore drills.

The 3-2-1 backup rule still holds in 2026. Keep three copies of data on two different media with one copy off-site. A single cron job dumping MySQL to the same disk as your database is not a backup strategy—it is a false sense of safety.

Document a one-page runbook. List backup paths, cron schedules, remote credentials location, and who gets alerted on failure. Store that runbook outside the server you are protecting.

How do you configure daily database and file backups on Ubuntu?

Start with a dedicated backup user, a fixed directory layout, and scripts that exit non-zero on failure. Cron only emails you when something breaks if the script fails correctly.

Create the backup directory and user

sudo mkdir -p /var/backups/{mysql,files,logs}
sudo chown -R backup:backup /var/backups
sudo chmod 750 /var/backups

Create a backup system user with read access to web roots and MySQL dump privileges. Never run backups as root unless you have no alternative.

MySQL dump script

For MySQL 9.7 on Ubuntu 24.04, use a credentials file instead of putting passwords in cron:

sudo nano /root/.my.cnf.backup
[client]
user=backup
password=STRONG_PASSWORD_HERE
host=localhost
sudo chmod 600 /root/.my.cnf.backup

Grant dump-only access:

CREATE USER 'backup'@'localhost' IDENTIFIED BY 'STRONG_PASSWORD_HERE';
GRANT SELECT, SHOW VIEW, TRIGGER, LOCK TABLES, EVENT, RELOAD ON *.* TO 'backup'@'localhost';
FLUSH PRIVILEGES;

Save the dump script at /usr/local/bin/backup-mysql.sh:

#!/bin/bash
set -euo pipedfail

BACKUP_DIR="/var/backups/mysql"
DATE=$(date +%Y-%m-%d_%H%M)
LOG="/var/backups/logs/mysql-${DATE}.log"
RETAIN_DAYS=14

mkdir -p "$BACKUP_DIR" /var/backups/logs

{
  echo "=== MySQL backup started: $(date) ==="
  for DB in $(mysql --defaults-extra-file=/root/.my.cnf.backup -N -e \
    "SELECT schema_name FROM information_schema.schemata \
     WHERE schema_name NOT IN ('information_schema','performance_schema','sys','mysql');"); do
    mysqldump --defaults-extra-file=/root/.my.cnf.backup \
      --single-transaction --routines --triggers --events \
      "$DB" | gzip > "${BACKUP_DIR}/${DB}_${DATE}.sql.gz"
    echo "Dumped: $DB"
  done
  find "$BACKUP_DIR" -name "*.sql.gz" -mtime +${RETAIN_DAYS} -delete
  echo "=== MySQL backup finished: $(date) ==="
} >> "$LOG" 2>&1
sudo chmod 750 /usr/local/bin/backup-mysql.sh
sudo chown root:backup /usr/local/bin/backup-mysql.sh

File backup with rsync

Sync application trees and config. Exclude cache and transient paths:

#!/bin/bash
set -euo pipefail

DATE=$(date +%Y-%m-%d)
DEST="/var/backups/files/${DATE}"
LOG="/var/backups/logs/files-${DATE}.log"
APPS="/var/www"

mkdir -p "$DEST" /var/backups/logs

{
  echo "=== File backup started: $(date) ==="
  rsync -aH --delete \
    --exclude 'node_modules/' \
    --exclude 'vendor/' \
    --exclude 'storage/framework/cache/' \
    --exclude 'storage/logs/' \
    --exclude 'bootstrap/cache/' \
    "${APPS}/" "${DEST}/apps/"
  rsync -aH /etc/nginx/ "${DEST}/nginx/" 2>/dev/null || true
  rsync -aH /etc/php/ "${DEST}/php/" 2>/dev/null || true
  echo "=== File backup finished: $(date) ==="
} >> "$LOG" 2>&1

Save that as /usr/local/bin/backup-files.sh. The rsync and cron automation guide covers incremental flags and bandwidth limits in more depth.

Schedule with cron

sudo crontab -e
# Daily MySQL dump at 02:15
15 2 * * * /usr/local/bin/backup-mysql.sh

# Daily file sync at 03:00
0 3 * * * /usr/local/bin/backup-files.sh

# Weekly config tarball Sunday 04:00
0 4 * * 0 tar -czf /var/backups/files/etc-$(date +\%Y-\%m-\%d).tar.gz /etc/nginx /etc/php /etc/cron.d

Stagger jobs so a heavy mysqldump does not overlap with rsync on a small VPS. On Rs 1,500/month (~USD 11) entry plans, I/O contention can push backups past the maintenance window.

Nightly Backup Pipeline02:15 Cronmysqldumpall app DBs03:00 rsyncapp + config04:00 rcloneoff-site pushLog + Alert on Non-Zero Exit/var/backups/logs/*.logEmail or webhook if job failsSilent cron = silent data loss
Stagger mysqldump, rsync, and off-site sync in your automated server backups complete setup to reduce I/O overlap.

Which backup tools work best for Laravel and WordPress servers?

Shell scripts plus cron remain the baseline on VPS hosting. Application-level tools add convenience but do not replace off-site copies.

ToolBest forOff-siteRestore speedOps overhead
Shell + mysqldump + rsyncAny PHP stack, full controlManual rclone/S3 stepFast local, medium remoteLow once scripted
Spatie Laravel BackupLaravel 12/13 appsS3, SFTP built-inGood with zip bundlesLow in-app config
WP-CLI + cronWordPress 7.1 sitesNeeds separate syncGood per siteLow per install
rclone onlyFile-heavy, no DB logicNativeDepends on remoteVery low

For Laravel, I regularly use Spatie Laravel Backup alongside server-level dumps. The package zips database and selected directories, then pushes to S3 or SFTP. Schedule it through the Laravel queue or scheduler so it does not fight with system cron.

Typical config/backup.php source paths for a Laravel 13 app:

'source' => [
    'files' => [
        'include' => [
            base_path(),
        ],
        'exclude' => [
            base_path('vendor'),
            base_path('node_modules'),
            storage_path('logs'),
        ],
    ],
    'databases' => ['mysql'],
],

Run via scheduler in routes/console.php or app/Console/Kernel.php on older apps:

Schedule::command('backup:run --only-db')->daily()->at('01:30');
Schedule::command('backup:clean')->daily()->at('05:00');
Schedule::command('backup:monitor')->daily()->at('06:00');

For WordPress 7.1, WP-CLI backup automation exports the database and syncs wp-content/uploads. WooCommerce 11.1 shops need the uploads tree and any custom order-export folders included.

On shared EC2 infrastructure where several legal-tech sites run the same Deployer 7 workflow, I keep one server-level script as the source of truth. App-level backups are a bonus layer, not the only layer.

Compare transport tools in the rsync vs rclone breakdown if you sync to object storage or a second VPS.

How do you automate off-site backups to S3 or remote storage?

Local archives protect against bad deploys and accidental deletes. They do not protect against datacenter fire, ransomware, or a stolen server image. Push encrypted copies off-site every night.

Install and configure rclone

sudo apt update && sudo apt install -y rclone
rclone config

Create a remote named s3-backups pointing at your bucket. Use a dedicated IAM user with write-only access to backups/ prefix. Never reuse production app credentials.

Upload script at /usr/local/bin/backup-offsite.sh:

#!/bin/bash
set -euo pipefail

REMOTE="s3-backups:prod-server-01"
LOCAL="/var/backups"
LOG="/var/backups/logs/offsite-$(date +%Y-%m-%d).log"

{
  echo "=== Off-site sync started: $(date) ==="
  rclone sync "$LOCAL/mysql" "${REMOTE}/mysql" \
    --transfers 4 --checkers 8 \
    --exclude "*.tmp"
  rclone sync "$LOCAL/files" "${REMOTE}/files" \
    --transfers 4 --checkers 8
  echo "=== Off-site sync finished: $(date) ==="
} >> "$LOG" 2>&1

Schedule at 04:30, after local jobs finish. The off-site S3 backup guide covers bucket policies, lifecycle rules, and cross-region replication.

Budget roughly Rs 800–2,500/month (~USD 6–19) for S3 storage on a small Laravel plus WordPress server. Exact cost depends on retention and upload volume. Use the JSON formatter to validate IAM policy documents before you apply them.

Encrypt sensitive dumps at rest with GPG before upload if compliance requires it:

gpg --symmetric --cipher-algo AES256 \
  /var/backups/mysql/myapp_2026-09-08.sql.gz

Store the GPG passphrase in your team vault, not on the server.

Local vs Off-Site RecoveryLocal OnlyFast rollbackBad deploy recoveryLost if disk diesOff-Site CopySurvives server lossRansomware safeSlower restoreUse Both: local for speed, off-site for survivalAlign with cloud DR planning
Automated server backups complete setup needs local speed plus off-site survival—one layer alone is not enough.

Align retention with your cloud disaster recovery plan. Match RPO and RTO targets to how often you sync and how fast you can rebuild a server from scratch.

How do you verify and restore automated server backups?

Untested backups are wishful thinking. Schedule a monthly restore drill to a staging VPS or local Docker MySQL container.

Database restore test

  1. Download the latest .sql.gz from off-site or copy from local archive
  2. Spin up a throwaway MySQL instance
  3. Import and run application smoke tests
  4. Log date, file name, duration, and any errors
gunzip -c /var/backups/mysql/myapp_2026-09-08.sql.gz | mysql -u root -p restore_test

For Laravel, run migrations status and hit a health route. For WordPress, load the admin login and check permalinks. On a production Laravel application I have restored this way, the gap between "backup exists" and "backup works" showed up within the first import—missing stored procedures or charset mismatches.

Full server rebuild checklist

When the VPS is gone, you rebuild in this order:

  1. Provision Ubuntu 24.04 with PHP 8.5 or 8.4 per app requirements
  2. Restore Nginx and PHP-FPM config from tarball
  3. Deploy code from Git or restore file archive
  4. Import latest MySQL dump
  5. Restore storage/ and upload directories
  6. Reload PHP-FPM, verify SSL with Certbot
  7. Run queue workers and cron

The Ubuntu PHP server setup guide covers base provisioning. Pair it with your backup runbook so rebuild time is measured, not guessed.

Projects like Notary Kathmandu and other sister sites on shared infrastructure share one backup playbook. That consistency matters when you are restoring under pressure at 2 AM.

How do you monitor backup jobs and harden the backup path?

A backup job that fails silently for three weeks is worse than no backup at all—you believe you are protected.

Monitoring options

  • Cron mail — set MAILTO=ops@yourdomain.com in root crontab
  • Exit-code wrappers — append || curl -X POST https://hooks.example/alert to scripts
  • File age checks — Nagios or a simple script alerts if newest dump is older than 26 hours
  • Log rotation — keep 30 days of backup logs under /var/backups/logs

Integrate with your wider Ubuntu server monitoring stack. Backup freshness belongs on the same dashboard as disk space and PHP-FPM status.

Lock down the backup path itself. Restrict SSH keys, disable password auth, and keep the backup user unable to write production code. Ransomware often targets connected backup directories first.

Follow server hardening practices and the broader website and server security guide. Backups do not replace patching, firewall rules, or TLS with Let's Encrypt.

Backup Monitoring FlowCron JobLog CheckAge AlertNotify OpsMonthly Restore DrillProve RTO before an incidentDocument results in runbook
Monitor backup job exit codes, file age, and logs—then validate with scheduled restore drills.

External references worth bookmarking: the MySQL 9.7 mysqldump documentation, the Ubuntu Server documentation, and rclone official docs for remote configuration flags.

If you want hands-off maintenance after setup, support and maintenance services and Linux system administration cover cron audits, restore drills, and alert tuning. Hosting setup should include backup scope in the SLA from day one.

Generate strong credentials for backup accounts with the password generator. Rotate them when staff changes.

Key Takeaways

  • Automated server backups complete setup needs database dumps, file sync, off-site copies, and retention—not just one mysqldump line in cron.
  • Stagger mysqldump, rsync, and rclone jobs to avoid I/O overlap on small VPS plans common in Nepal.
  • Layer Spatie Laravel Backup or WP-CLI exports on top of server-level scripts for application-specific bundles.
  • Push encrypted archives to S3 or a remote VPS nightly; local-only copies fail when the server dies.
  • Run a monthly restore drill and log results—untested backups are not backups.
  • Monitor job exit codes and dump file age; alert before you discover data loss during an incident.

People Also Ask

How often should server backups run?

Daily full database dumps suit most Laravel and WordPress sites. High-traffic eCommerce may need hourly binlog shipping or more frequent incremental sync. Match frequency to your recovery point objective—the maximum data loss you can accept.

What is the best backup retention policy?

A practical default is 14 daily, 8 weekly, and 12 monthly copies. Adjust for compliance and storage cost. Lifecycle rules on S3 buckets automate expiry so old objects do not inflate your bill.

Should backups include vendor and node_modules directories?

No. Exclude vendor/, node_modules/, and cache paths. Rebuild them with composer install and npm ci after restore. Including them wastes space and slows every sync.

Can I rely on hosting panel backups alone?

Panel snapshots help, but they are often local to the provider, opaque, and hard to test. Keep your own scripted dumps you control, verify, and can download. Treat panel backups as a secondary layer.

Build a backup stack you can trust under pressure

An automated server backups complete setup is finished only when a restore succeeds on a clean server—not when cron runs without errors. Script the dumps, sync off-site, monitor freshness, and drill monthly. Pair this with Ubuntu security practices and CIS hardening benchmarks so the data you protect stays reachable.

Need help wiring this on a production stack or auditing an existing cron setup? Contact us for backup review, restore testing, and ongoing server maintenance. Browse the portfolio for examples of live systems running these patterns, or read more on the blog.

Frequently Asked Questions

It schedules database dumps and file sync via cron, copies archives off-site with rsync or rclone, applies retention rules, logs every run, and includes a monthly restore test so recovery is proven—not assumed.

Budget roughly Rs 800–2,500/month (~USD 6–19) for S3 storage on a small Laravel plus WordPress server. Exact cost depends on retention length and upload volume; lifecycle rules on the bucket help stop old objects inflating the bill.

Think in layers: local hot copies for fast rollback, off-site warm copies for server loss, and a written restore path stored outside the protected server. Back up four asset classes—MySQL 9.7 or MariaDB 12.3 databases, application files including .env and uploads outside Git, Nginx or Apache vhosts plus PHP-FPM pools and cron entries, and a secrets inventory of disk-only credentials. On legal-tech portals I maintain, uploaded PDFs in storage/app often matter more than row counts. Follow the 3-2-1 rule: three copies on two media with one off-site. A mysqldump to the same disk as the database is not a strategy.

Create a dedicated backup user, directory layout under /var/backups with mysql, files, and logs subdirectories, and scripts that exit non-zero on failure so cron alerts you. Use a chmod 600 credentials file for mysqldump instead of passwords in cron. Grant the backup MySQL user dump-only privileges. Save backup-mysql.sh and backup-files.sh under /usr/local/bin with rsync excluding vendor, node_modules, and cache paths. Schedule cron at 02:15 for MySQL, 03:00 for files, and a weekly /etc tarball Sunday at 04:00. Stagger jobs so heavy dumps do not overlap rsync on small VPS plans.

Shell scripts plus mysqldump and rsync remain the baseline on VPS hosting because they give full control and fast local restores. For Laravel 12 or 13, Spatie Laravel Backup zips database and selected directories and pushes to S3 or SFTP via the scheduler—schedule it away from system cron. For WordPress 7.1, WP-CLI exports the database and syncs wp-content/uploads; WooCommerce 11.1 shops need uploads and custom order-export folders. On shared EC2 infrastructure where several sites share a Deployer 7 pipeline, I keep one server-level script as source of truth and treat app-level backups as a bonus layer, not the only layer.

Install rclone, create a remote such as s3-backups with a dedicated IAM user limited to write-only access on a backups/ prefix—never reuse production app credentials. Write backup-offsite.sh to rclone sync local /var/backups/mysql and /var/backups/files to the remote with transfers and checkers tuned, logging each run. Schedule at 04:30 after local jobs finish. If compliance requires it, encrypt sensitive dumps with GPG AES256 before upload and store the passphrase in your team vault, not on the server. Align sync frequency and retention with your RPO and RTO targets from your disaster recovery plan.

Untested backups are wishful thinking. Schedule a monthly restore drill to a staging VPS or throwaway MySQL instance: download the latest .sql.gz from off-site or copy locally, import with gunzip piped to mysql, then log date, filename, duration, and errors. For Laravel, check migration status and hit a health route. For WordPress, load admin and verify permalinks. I have seen missing stored procedures or charset mismatches surface on first import. For full server loss, rebuild in order: provision Ubuntu 24.04 with PHP 8.5 or 8.4, restore Nginx and PHP-FPM config, deploy code from Git or file archive, import MySQL, restore storage and uploads, reload PHP-FPM, verify SSL with Certbot, then restart queue workers and cron.

A backup that fails silently for three weeks is worse than no backup. Set MAILTO in root crontab for cron mail, wrap scripts with exit-code alerts via webhook curl on failure, and run file-age checks alerting if the newest dump is older than 26 hours. Keep 30 days of logs under /var/backups/logs. Put backup freshness on the same dashboard as disk space and PHP-FPM status. Harden the path itself: restrict SSH keys, disable password auth, and ensure the backup user cannot write production code—ransomware often targets connected backup directories first. Backups complement patching, firewall rules, and Let's Encrypt TLS; they do not replace them.

Daily full database dumps suit most Laravel and WordPress sites. High-traffic eCommerce may need hourly binlog shipping or more frequent incremental sync. Match frequency to your recovery point objective—the maximum acceptable data loss.

A practical default is 14 daily, 8 weekly, and 12 monthly copies, adjusting for compliance and storage cost. The sample MySQL script uses RETAIN_DAYS=14 with find deleting older .sql.gz files automatically. On S3, lifecycle rules expire old objects so retention does not inflate your Rs 800–2,500/month (~USD 6–19) storage bill. Document retention in your one-page runbook alongside cron schedules and alert contacts. Retention should reflect how far back you realistically need to roll—a bad deploy yesterday needs a different window than an audit asking for last quarter's data.

No. Exclude vendor/, node_modules/, and cache paths such as storage/framework/cache and bootstrap/cache. Rebuild them with composer install and npm ci after restore. Including them wastes space and slows every rsync and off-site sync.

Panel snapshots help for quick rollback, but they are often local to the provider, opaque about what is inside, and hard to test on a schedule you control. Keep your own scripted dumps with mysqldump and rsync that you can download, verify monthly, and restore to a staging VPS. On Rs 1,500/month (~USD 11) entry VPS plans common in Nepal, provider snapshots may not cover every database, upload directory, or Nginx vhost change you made outside the panel. Your runbook should list paths, credentials location, and who gets alerted—stored outside the server you are protecting.

On Rs 1,500/month (~USD 11) entry plans, I/O contention from overlapping mysqldump, rsync, and rclone can push backups past the maintenance window and starve live PHP-FPM workers during peak hours. Stagger MySQL dumps at 02:15, file sync at 03:00, weekly config tarballs Sunday at 04:00, and off-site rclone sync at 04:30 so each job finishes before the next heavy task starts. This pattern keeps nightly automation reliable without upgrading hardware. If backups still overrun, reduce rsync scope or add bandwidth limits rather than running everything at midnight.

Yes. Keep three copies of data on two different media with one copy off-site. A single cron job dumping MySQL to the same disk as your database gives false safety—it protects against application mistakes but not disk failure, datacenter loss, or ransomware wiping the server. A complete automated setup combines local archives under /var/backups for fast rollback, nightly rclone sync to S3 or a remote VPS for survival, and a documented restore path tested monthly. That layered approach matches what I run on Ubuntu servers hosting Laravel and WordPress production stacks, including sister sites on a shared Deployer 7 pipeline.

Use server-level mysqldump and rsync as the authoritative layer because they capture every database and config on the box, not just one app. Layer Spatie Laravel Backup on Laravel 12 or 13 apps for convenient zip bundles pushed to S3 or SFTP via backup:run, backup:clean, and backup:monitor scheduled through Laravel's scheduler—typically at 01:30, 05:00, and 06:00 so they do not fight system cron. Configure config/backup.php to include the app base path while excluding vendor, node_modules, and storage/logs. On shared infrastructure running multiple sites, one server script protects the whole host; app packages add per-project bundles without replacing off-site copies.

Share this article

0 Comments

Leave a comment

Your email is not published. Comments appear once they have been read. Sign in to have your details filled in.

Quick Contact Options
Choose how you want to connect me: