A Robust Linux Backup Script

Creating a reliable Linux backup script sounds simple — until tar starts throwing errors like:

tar: /etc/pdns*: Cannot stat: No such file or directory
tar: Exiting with failure status due to previous errors

In production environments, these small issues can cause failed backups, missed alerts, and serious operational risks.

In this guide, we’ll walk through:

  • How to build a production-ready Linux backup script
  • Why tar wildcard errors happen
  • How to eliminate Cannot stat failures
  • How to include OS version and installed packages in backups
  • How to safely upload backups via FTP
  • How to integrate email reporting
  • Best practices for stable, enterprise-grade backup automation

All examples are anonymized and suitable for Oracle Linux, RHEL, CentOS, or similar distributions.


Why Backup Scripts Fail in Production

Many backup scripts fail due to one common mistake:

❌ Using wildcard paths that do not exist

Example:

/etc/pdns*
/etc/python*

If these directories don’t exist on the system, tar interprets them as literal paths and fails.

This results in:

tar: Cannot stat
tar: Exiting with failure status due to previous errors

In production, this means:

  • Backup marked as failed
  • Email alert triggered
  • No valid backup uploaded
  • False alarms or worse — silent failures

Best Practice: Never Use Unverified Wildcards

Instead of using:

/etc/php*
/etc/pdns*

Use only verified existing directories:

/etc/php.d
/etc/php.ini
/etc/httpd
/etc/my.cnf
/etc/my.cnf.d

This eliminates wildcard expansion issues entirely.


What a Production-Ready Backup Script Should Include

A professional Linux backup script should include:

1. MySQL/MariaDB dump

2. OS version information

3. Installed package list

4. Configuration files

5. Web application files

6. Email reporting

7. FTP or remote upload

8. Clean exit codes


Example: Stable Linux Backup Script (Zero Wildcard Errors)

Below is a simplified, production-safe example.

#!/bin/bash -e

EMAIL_TO="admin@example.com"
TODAY=$(date +%Y%m%d)
HOST=$(hostname -s)

BACKUP_FILE="/usr/local/src/${HOST}-${TODAY}.tgz"
LOGFILE="/var/log/backup_${TODAY}.log"

exec > "$LOGFILE" 2>&1

send_mail() {
  mail -s "$1" -a "$LOGFILE" "$EMAIL_TO"
}

echo "Starting backup..."

# MySQL dump
mysqldump -u backupuser -p'StrongPassword' --all-databases > /usr/local/src/alldb.sql

# OS version
cat /etc/*release > /usr/local/src/os_version.info

# Installed packages
rpm -qa > /usr/local/src/installed_packages.info

# Safe directories (NO wildcards)
BACKUP_PATHS=(
/var/www
/etc/php.d
/etc/php.ini
/etc/hosts
/etc/httpd
/etc/my.cnf
/etc/my.cnf.d
/etc/sysconfig/network
/etc/firewalld
/usr/local/src
)

tar -czvf "$BACKUP_FILE" \
    /usr/local/src/os_version.info \
    /usr/local/src/installed_packages.info \
    /usr/local/src/alldb.sql \
    "${BACKUP_PATHS[@]}"

# FTP upload
ncftpput -u ftpuser -p ftppass ftp.example.com \
    /NetBackup/server_folder "$BACKUP_FILE"

rm -f "$BACKUP_FILE"

send_mail "Backup successful on $HOST"

Why This Script Never Fails With “Cannot stat”

Because:

  • No wildcard paths are used
  • Only guaranteed existing directories are included
  • Arrays ("${BACKUP_PATHS[@]}") are used properly
  • No glob expansion issues
  • No quoting mistakes
  • No dynamic path assumptions

How to Include OS Version and Installed Packages

Including system metadata makes disaster recovery much easier.

OS Version

cat /etc/*release > os_version.info

This captures:

  • Distribution name
  • Version
  • Kernel compatibility

Example output:

Oracle Linux Server release 7.9
NAME="Oracle Linux Server"
VERSION="7.9"

Installed Packages

rpm -qa > installed_packages.info

This allows full environment reconstruction.

Example snippet:

httpd-2.4.6-97.el7.x86_64
php-7.4.33-1.el7.x86_64
mysql-community-server-8.0.36.x86_64

During restore, you can reinstall:

dnf install package-name

How to Avoid FTP Upload Failures

Always use:

ncftpput -u USER -p PASS -m host remote_path file

Key points:

  • -m creates remote directory if missing
  • Always verify remote path exists
  • Use full absolute remote paths
  • Do not dynamically generate folder names unless required

Example correct remote path:

/NetBackup/192.168.50.121_servername.domain

Common Mistakes That Break Backup Scripts

❌ Using multi-line strings with quotes

FILESTOBACKUP='
/etc/php*
'

❌ Using unverified wildcard directories

/etc/pdns*

❌ Relying on eval

$(eval echo $FILESTOBACKUP)

❌ Including directories that do not exist

❌ Forgetting to check exit codes


Incremental vs Full Backups

Full Backup

Includes everything:

tar -czvf backup-full.tgz ...

Incremental Backup

Includes only recently modified files:

find /var/www -mtime -1

Use incremental carefully — only if you understand retention strategy.


Recommended Backup Architecture

For production environments:

  • Daily full backups
  • Weekly offsite transfer
  • 30-day retention
  • Separate DB and file backups
  • Encrypted archives (optional)
  • Restore script included but NOT executed automatically

Disaster Recovery Workflow Example

  1. Provision new server
  2. Install base OS
  3. Install packages from installed_packages.info
  4. Restore database:
    mysql < alldb.sql
    
  5. Restore configuration files
  6. Restart services
  7. Validate applications

Final Recommendations

✔ Never use unsafe wildcards
✔ Always log output
✔ Always email status
✔ Always verify remote upload
✔ Include system metadata
✔ Keep restore script separate from backup logic
✔ Test restore regularly


Conclusion

Building a stable Linux backup script requires attention to small technical details — especially how tar handles wildcards.

The difference between:

/etc/pdns*

and

/etc/php.d

can determine whether your backup succeeds or silently fails.

A production-ready script should be:

  • Deterministic
  • Predictable
  • Explicit
  • Free from glob expansion errors
  • Fully logged
  • Fully monitored

When built correctly, your backup system becomes reliable, auditable, and disaster-ready.

This article is inspired by real-world challenges we tackle in our projects. If you're looking for expert solutions or need a team to bring your idea to life,

Let's talk!

    Please fill your details, and we will contact you back

      Please fill your details, and we will contact you back