A secure, automated backup solution for web applications and MySQL/MariaDB databases with encrypted cloud storage. Supports multiple hosting panels and application types.
By Backupd
This tool provides a complete backup solution for web hosting environments:
- Database Backups β Dumps all MySQL/MariaDB databases, encrypted and deduplicated by restic, stored via rclone to cloud storage
- File Backups β Archives web applications (WordPress, Laravel, Node.js, PHP, etc.) with restic deduplication and encryption
- Secure Credential Storage β All credentials (database, cloud storage) are encrypted with AES-256 and bound to your server's machine-id
- Automated Scheduling β Uses systemd timers for reliable, automatic backups with retry on failure
- Retention & Cleanup β Automatic deletion of old backups based on configurable retention policy
- Backup Verification β Weekly quick checks (no download), monthly reminders to test restorability
- Easy Restore β Interactive wizard to browse and restore from any backup point
- Notifications β Optional alerts via ntfy.sh push notifications AND/OR custom webhooks
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
β Your Server β
β ββββββββββββ ββββββββββββββββββββββββββββββ ββββββββββββ β
β β Database βββββΆβ Restic ββββ rclone ββββΌβββΆ Cloud Storage
β β Dump β β (encrypt + dedup + verify) β β(transport)β β (S3/B2/etc)
β ββββββββββββ ββββββββββββββββββββββββββββββ ββββββββββββ β
β β
β ββββββββββββ ββββββββββββββββββββββββββββββ ββββββββββββ β
β β Web βββββΆβ Restic ββββ rclone ββββΌβββΆ Cloud Storage
β β Apps β β (encrypt + dedup + verify) β β(transport)β β
β ββββββββββββ ββββββββββββββββββββββββββββββ ββββββββββββ β
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
v3.0 Architecture: Restic handles all backup operations (encryption, deduplication, verification). rclone provides cloud storage transport to 40+ providers. See CHANGELOG.md for details.
Panel backups fail silently. Whether you're using cPanel, Plesk, Enhance, xCloud, or any other hosting panel β their built-in backup systems can fail without warning. You need an independent backup layer that:
- Works alongside (not instead of) your panel's backups
- Stores backups off-server in cloud storage
- Encrypts sensitive data (database credentials, backups)
- Runs automatically on a schedule
- Notifies you of success or failure
This tool provides exactly that.
- ποΈ Database Backups β All MySQL/MariaDB databases, individually compressed and encrypted
- π Web App File Backups β Backs up any web application (WordPress, Laravel, Node.js, PHP, static sites)
- π₯οΈ Multi-Panel Support β Auto-detects Enhance, xCloud, RunCloud, Ploi, cPanel, Plesk, CloudPanel, CyberPanel, aaPanel, HestiaCP, FlashPanel, Virtualmin
- π§ Multi-Distribution Support β Works on Debian, Ubuntu, Fedora, RHEL, CentOS, Arch, Alpine, openSUSE and derivatives
- π Machine-Bound Encryption β Credentials encrypted with AES-256, tied to your server
- βοΈ Cloud Storage β Supports 40+ providers via rclone (S3, B2, Wasabi, Google Drive, etc.)
- β° Automated Scheduling β Systemd timers with automatic retry and catch-up
- π§Ή Retention & Cleanup β Configurable retention policy with automatic old backup deletion
- β Integrity Verification β SHA256 checksums, quick checks (no download), and monthly full test reminders
- π Triple-Channel Notifications β Optional alerts via ntfy.sh, Pushover, AND/OR custom webhooks on backup events
- π Easy Restore β Interactive restore wizard with safety backups and checksum verification
- π Detailed Logging β Full logs with timestamps and automatic log rotation
- π Auto-Update β Built-in update system with version checking and one-click updates
curl -fsSL https://raw.githubusercontent.com/wnstify/backupd/main/install.sh | sudo bashThen run the setup wizard:
sudo backupdThat's it! The wizard will guide you through configuration.
curl -fsSL https://raw.githubusercontent.com/wnstify/backupd/develop/install.sh | sudo bash -s -- --branch develop| Requirement | Notes |
|---|---|
| OS | Ubuntu, Debian, Fedora, RHEL, CentOS, Arch, Alpine, openSUSE (and derivatives) |
| Access | Root or sudo |
| MySQL/MariaDB | For database backups |
| systemd | For scheduled backups (optional, manual backups work without) |
| curl or wget | At least one required for downloads |
| restic | Auto-installed (backup engine with encryption + deduplication) |
| rclone | Auto-installed (cloud storage transport) |
| argon2 | Auto-installed (modern encryption, falls back to PBKDF2 if unavailable) |
| bzip2, unzip | Auto-installed (for extracting restic and rclone) |
/etc/backupd/
βββ backupd.sh # Main script (entry point)
βββ lib/ # Modular library
β βββ core.sh # Colors, validation, helpers
β βββ logging.sh # Structured logging with auto-redaction
β βββ debug.sh # Legacy debug logging
β βββ crypto.sh # Encryption, secrets
β βββ config.sh # Configuration read/write
β βββ generators.sh # Script generation
β βββ status.sh # Status display
β βββ backup.sh # Backup execution
β βββ verify.sh # Integrity verification
β βββ restore.sh # Restore execution
β βββ schedule.sh # Schedule management
β βββ setup.sh # Setup wizard
β βββ updater.sh # Auto-update functionality
β βββ cli.sh # CLI subcommand dispatcher
β βββ notifications.sh # Notification configuration
βββ .config # Configuration (retention, paths, etc.)
βββ scripts/
β βββ db_backup.sh # Database backup script
β βββ db_restore.sh # Database restore script
β βββ files_backup.sh # Files backup script
β βββ files_restore.sh # Files restore script
β βββ verify_backup.sh # Quick integrity check (weekly)
β βββ verify_reminder.sh # Full test reminder (monthly)
βββ logs/
βββ db_logfile.log # Database backup logs (auto-rotated)
βββ files_logfile.log # Files backup logs (auto-rotated)
βββ verify_logfile.log # Verification logs (auto-rotated)
βββ notification_failures.log # Failed notification attempts
/var/log/backupd.log # Structured error log (auto-created)
/etc/.{random}/ # Encrypted secrets (hidden, immutable)
βββ .s # Salt for key derivation
βββ .algo # Encryption version (1, 2, or 3)
βββ .c1 # Encryption passphrase
βββ .c2 # Database username
βββ .c3 # Database password
βββ .c4 # ntfy token (optional)
βββ .c5 # ntfy URL (optional)
βββ .c6 # webhook URL (optional)
βββ .c7 # webhook auth token (optional)
βββ .c8 # Pushover user key (optional)
βββ .c9 # Pushover API token (optional)
/usr/local/bin/backupd # Symlink for easy access
/etc/systemd/system/
βββ backupd-db.service
βββ backupd-db.timer
βββ backupd-files.service
βββ backupd-files.timer
βββ backupd-verify.service # Weekly quick check
βββ backupd-verify.timer
βββ backupd-verify-full.service # Monthly reminder (no download)
βββ backupd-verify-full.timer
sudo backupdβββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
β Backupd v3.1.0 β
β by Backupd β
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
Main Menu
=========
1. Run backup now
2. Restore from backup
3. Verify backups
4. View status
5. View logs
6. Manage schedules
7. Notifications
8. Reconfigure
9. Uninstall
U. Update tool
0. Exit
# Backup commands
sudo backupd backup db # Backup databases
sudo backupd backup files # Backup files
sudo backupd backup all # Backup both
# Restore commands
sudo backupd restore db # Restore database
sudo backupd restore files # Restore files
sudo backupd restore db --list # List available backups
# Status and verification
sudo backupd status # Show system status
sudo backupd verify # Quick verification
sudo backupd verify --full # Full verification
# Schedule management
sudo backupd schedule list # List active schedules
sudo backupd schedule enable # Enable schedules
sudo backupd schedule disable # Disable schedules
# View logs
sudo backupd logs # View all logs
sudo backupd logs db --lines 50 # Last 50 lines of db log
# Backup history
sudo backupd history # Last 20 operations
sudo backupd history db -n 50 # Last 50 database backups
sudo backupd history verify # Verification history
sudo backupd history --json # JSON output for APIs
# Multi-job management (v3.1.0)
sudo backupd job list # List all jobs
sudo backupd job show <name> # Show job details
sudo backupd job create <name> # Create new job
sudo backupd job clone <src> <dst> # Clone job config
sudo backupd job run <name> db # Run backup for job--quiet, -q # Suppress non-essential output (for scripts/cron)
--json # Output in JSON format (for parsing)
--dry-run, -n # Preview operations without executing
--help, -h # Show help message
--version, -v # Show version information# Trigger database backup
sudo systemctl start backupd-db
# Trigger files backup
sudo systemctl start backupd-files# Database backup logs
sudo journalctl -u backupd-db -f
# Files backup logs
sudo journalctl -u backupd-files -f
# Or via menu
sudo backupd # Select "View Logs"# List active timers
systemctl list-timers | grep backupd
# Check specific timer
systemctl status backupd-db.timerAll operations are automatically logged to /var/log/backupd.log with sensitive data redacted.
# View recent logs
sudo tail -f /var/log/backupd.log
# Verbose output (DEBUG level)
sudo backupd --verbose backup db
# Very verbose output (TRACE level with function tracing)
sudo backupd -vv backup db
# Export sanitized log for GitHub issues
sudo backupd --log-exportLog features:
- Automatic error logging on every run
- Function name, line number, and stack traces
- Auto-redaction of passwords, tokens, paths, and secrets
- System info (OS, bash version, tool versions)
- GitHub Issues-compatible export format
See DEBUG.md for comprehensive troubleshooting guide.
Modern encryption (v2.1.0+):
βββββββββββββββββββ ββββββββββββββββ βββββββββββββββββββ
β machine-id ββββββΆβ + salt ββββββΆβ Argon2id β
β (unique/server)β β (random) β β (derived key) β
βββββββββββββββββββ ββββββββββββββββ ββββββββββ¬βββββββββ
β
βΌ
βββββββββββββββββββ ββββββββββββββββ βββββββββββββββββββ
β Your secrets ββββββΆβ AES-256 ββββββΆβ .enc files β
β (credentials) β β + PBKDF2 β β (encrypted) β
βββββββββββββββββββ ββββββββββββββββ βββββββββββββββββββ
Protection includes:
- Strong password requirements β 12+ characters, 2+ special characters (enforced)
- Argon2id key derivation (memory-hard, GPU/ASIC resistant) β default when
argon2installed - PBKDF2-SHA256 fallback (800,000 iterations) β if argon2 not available
- AES-256-CBC encryption for all credentials
- Machine-bound keys (won't decrypt on another server)
- Random directory names (
/etc/.{random}/) - Immutable file flags (
chattr +i) - No plain-text credentials stored anywhere
Encryption management:
# Check current encryption status
sudo backupd --encryption-status
# Upgrade existing installation to modern encryption
sudo backupd --migrate-encryption| Threat | Protected? |
|---|---|
| Casual file browsing | β Yes |
| Automated scanners | β Yes |
| Credential reuse attacks | β Yes |
| Server migration/cloning | β Yes (credentials don't transfer) |
| Attacker with root access |
If an attacker gains root access to your running server, they could potentially:
- Extract the machine-id and salt
- Derive the encryption key
- Decrypt the credentials
This is a fundamental limitation β no solution can fully protect secrets on a compromised server where the secrets must be usable. Our approach raises the bar significantly and stops opportunistic attacks, but it's not impenetrable against a determined attacker with full system access.
- Use SSH keys (disable password auth)
- Enable firewall (ufw/iptables)
- Install fail2ban
- Keep system updated
- Enable 2FA on your cloud storage provider
- Regularly rotate credentials
The tool uses rclone which supports 40+ cloud providers:
| Provider | Command |
|---|---|
| Backblaze B2 | rclone config β "b2" |
| AWS S3 | rclone config β "s3" |
| Wasabi | rclone config β "s3" (Wasabi endpoint) |
| Google Drive | rclone config β "drive" |
| Dropbox | rclone config β "dropbox" |
| SFTP | rclone config β "sftp" |
The setup wizard will guide you through rclone configuration, or you can run:
rclone configSchedules are managed via systemd timers. Available presets:
| Option | Schedule |
|---|---|
| Hourly | Every hour |
| Every 2 hours | *-*-* 0/2:00:00 |
| Every 6 hours | *-*-* 0/6:00:00 |
| Daily at midnight | *-*-* 00:00:00 |
| Daily at 3 AM | *-*-* 03:00:00 |
| Weekly (Sunday) | Sun *-*-* 00:00:00 |
| Custom | Any systemd OnCalendar expression |
Recommended:
- Database backups: Every 2 hours
- File backups: Daily at 3 AM
Automatic cleanup of old backups based on configurable retention periods:
| Option | Retention Period |
|---|---|
| 1 minute | Testing only |
| 1 hour | Testing only |
| 7 days | Short-term |
| 14 days | Default recommended |
| 30 days | Standard |
| 60 days | Extended |
| 90 days | Long-term |
| 365 days | Annual |
| Disabled | No automatic cleanup |
- After each backup β Old backups are automatically checked and deleted
- Based on file age β Uses the backup file's modification time
- Safe cleanup β Restic retention policies (
restic forget --prune) safely remove old snapshots
sudo backupd # Select "Manage schedules" β "Change retention policy"Or run manual cleanup:
sudo backupd # Select "Run backup now" β "Run cleanup now"The status page shows your current retention policy:
Retention Policy:
β Retention: 30 days
sudo backupd # Select "Restore from Backup"The restore wizard:
- Lists available backups from cloud storage
- Downloads selected backup
- Creates a safety backup of current data
- Decrypts and extracts (for databases)
- Restores to original location
- Verifies restoration
Always test restores before you need them!
The database backup contains table structures and data only. It does NOT contain MySQL users or permissions.
| Scenario | Will Restore Work? |
|---|---|
| Tables deleted, database exists | Yes |
| Database deleted, user exists | Yes (if backup has CREATE DATABASE) |
| Database AND user deleted | No β user/grants must be recreated first |
If you deleted the database AND the database user, you must manually recreate them before restoring:
# 1. Create the database
mysql -u root -p -e "CREATE DATABASE mydb;"
# 2. Create the user
mysql -u root -p -e "CREATE USER 'myuser'@'localhost' IDENTIFIED BY 'password';"
# 3. Grant permissions
mysql -u root -p -e "GRANT ALL PRIVILEGES ON mydb.* TO 'myuser'@'localhost';"
mysql -u root -p -e "FLUSH PRIVILEGES;"
# 4. Now run the restore via backupd menu
sudo backupd # Select "Restore from Backup" β "Database"Important: The database credentials must match what's in your application's config file (wp-config.php for WordPress, .env for Laravel, etc.). If you create a new user with different credentials, update your application config accordingly.
This is standard behavior for database backup tools β they backup data, not MySQL system users.
Optional push notifications via ntfy.sh and/or custom webhooks. Both channels can be used simultaneously for redundancy.
Access the dedicated Notifications menu from the main menu (option 7):
Notifications
=============
Current Configuration:
β ntfy: https://ntfy.sh/your-topic...
β Webhook: https://your-webhook.com/...
Options:
1. Configure ntfy
2. Configure webhook
3. Test notifications
4. View notification failures
5. Disable all notifications
0. Back to main menu
- Install ntfy app on your phone (iOS / Android)
- Subscribe to a unique topic (e.g.,
myserver-backups-secret123) - Configure in backupd: Main Menu β Notifications β Configure ntfy
- Receive alerts on backup success/failure
Send backup events to any webhook endpoint (n8n, Slack, Discord, custom APIs):
- Main Menu β Notifications β Configure webhook
- Enter your webhook URL (HTTPS required)
- Optionally add a Bearer token for authentication (most webhooks don't need this)
- Receive JSON payloads with event details
Webhook JSON payload:
{
"event": "backup_complete",
"title": "Database Backup Complete",
"hostname": "server.example.com",
"message": "All 5 databases backed up successfully",
"timestamp": "2025-12-20T03:00:00+01:00",
"details": {"count": 5, "duration": "45s"}
}| Category | Events |
|---|---|
| DB Backup | started, complete, warning, failed, retention_cleanup, retention_failed |
| Files Backup | started, complete, warning, failed, retention_cleanup, retention_failed |
| Verification | passed, warning, failed, needs_full, never_tested, overdue |
| System | setup_complete, test |
- Dual-channel delivery β Both ntfy and webhook can be configured for redundancy
- Retry with backoff β Failed sends retry 3 times with exponential backoff (1s, 2s, 4s)
- Failure logging β All failed notifications logged to
logs/notification_failures.log - HTTP validation β Only 2xx responses count as success (not just "no error")
- Test function β Send test notifications to verify configuration
- All notification URLs must use HTTPS (enforced)
- Webhook tokens are encrypted with AES-256 (same as database credentials)
- No sensitive data (passwords, paths) included in notifications
Note: Notifications are completely optional. All backup, restore, and verification operations work normally without notifications configured.
curl -fsSL https://raw.githubusercontent.com/wnstify/backupd/main/install.sh | sudo bash -s -- --uninstallYou'll be asked whether to keep or remove configuration and secrets.
- CHANGELOG.md β Version history and changes
- USAGE.md β Detailed usage guide
- DEBUG.md β Logging and troubleshooting guide
- SECURITY.md β Security policy and best practices
- DISCLAIMER.md β Legal disclaimer and responsibilities
- π Issues: GitHub Issues
- π§ Email: support@webnestify.cloud
- π Website: backupd.io
MIT License β see LICENSE
Contributions welcome! Please read the code of conduct and submit PRs to the develop branch.
Built with care by Backupd