- Shell 99%
- Dockerfile 1%
| Filename | Latest commit message | Latest commit date |
|---|---|---|
| bin | ||
| docs | ||
| etc | ||
| logrotate | ||
| scripts | ||
| servers | ||
| systemd | ||
| tests | ||
| .gitignore | ||
| CHANGELOG.md | ||
| CLAUDE.md | ||
| deploy.sh | ||
| install.sh | ||
| LICENSE | ||
| README.md | ||
clpbackup
Per-site restic backups for CloudPanel servers, with restores that can bring back a completely deleted site.
Written by: René Kreijveld.
For every site, one snapshot contains:
- the website files:
/home/<siteuser>/, without logs, caches and tmp directories (seeetc/excludes.txt) - the database(s): a fresh
mariadb-dumpof every database of the site - the CloudPanel configuration: the site's data from CloudPanel's SQLite database (PHP settings, vhost template, databases and users, cron jobs, FTP/SSH users, certificate, basic auth, blocked IPs/bots, Varnish settings), plus the nginx vhost, PHP-FPM pool, SSL certificate and crontab
Backups go to two independent restic repositories: a local one on the server and an offsite one (any restic backend; SFTP on a Hetzner Storage Box is used as the example in the docs).
| Destination | When (defaults) | Retention (defaults) |
|---|---|---|
Local: /var/backups/clpbackup/repo |
02:00 | 5 daily backups |
| Offsite | 02:00, 08:00, 14:00 and 20:00 | everything from the last 7 days + 4 weekly + 12 monthly |
| Manual backups (both) | whenever you want | 30 days |
Errors and warnings are mailed. Every week restic check verifies both repositories.
Features
- Sites are discovered automatically from CloudPanel; new sites are backed up without configuration.
- Restore without risk: by default a restore only extracts the backup to a separate directory.
- In-place restore of files, database and/or config, after confirmation and an automatic safety backup of the current state. nginx and PHP-FPM configs are tested before they go live.
- Deleted site?
restorerecreates it withclpctl(site, databases, database users), restores everything and adjusts the PHP-FPM port where needed. - Keeps the CloudPanel UI consistent: config restores update CloudPanel's own database too.
remove-site-backupscleans up all backups of a site that no longer exists.
Requirements
- Ubuntu 24.04 with CloudPanel 2.x (tested with CloudPanel 2.5.4, MariaDB 10.11 and 11.4)
- An offsite restic repository (SFTP, S3, B2, REST server, ...)
- Optional: a working MTA (e.g. Postfix) for mail notifications
install.sh installs the other dependencies (sqlite3, jq, rsync, bzip2, curl) and a
pinned, checksum-verified version of restic.
Quick start
git clone <this repository> clpbackup && cd clpbackup
cp etc/clpbackup.conf.example servers/server1.conf # edit: SERVER_NAME, OFFSITE_REPO, MAIL_TO, ...
./deploy.sh root@server1 # copies the files and runs install.sh
Then, on the server as root:
clpbackup setup-mysql # MariaDB access (password from: clpctl db:show:master-credentials)
clpbackup init # create repository passwords and repositories
clpbackup backup --all # first backup
bash ~/clpbackup-src/install.sh --enable-timers
Store /etc/clpbackup/local.pass and offsite.pass in your password manager. Without them
the backups cannot be restored.
Daily use:
clpbackup status # last backup per site
clpbackup backup www.example.com # manual backup
clpbackup snapshots www.example.com --offsite # available backups
clpbackup restore www.example.com --from local # extract to /var/backups/clpbackup/restore/
clpbackup remove-site-backups www.old-site.com # remove backups of a deleted site
clpbackup help
Documentation
- docs/installation.md: installing, connecting a server, updating
- docs/manual-backup.md: manual backups, what is in a backup, retention, removing a site
- docs/restore.md: restoring from the local or offsite backup, all scenarios plus disaster recovery
- PDF versions are in
docs/pdf/(rebuild withdocs/build-pdf.sh)
Repository layout
bin/clpbackup the tool (bash)
etc/clpbackup.conf.example config template
etc/excludes.txt default excludes
servers/ per-server configs (servers/<hostname -s>.conf)
systemd/ services; install.sh generates the timers from the config
logrotate/clpbackup
install.sh install/update on the server (as root)
deploy.sh <ssh-host> copy to the server and run install.sh
scripts/inventory.sh read-only inventory of a server before installing
tests/run-docker-tests.sh functional tests in a disposable Docker container
On the server
/usr/local/sbin/clpbackup /usr/local/bin/restic
/etc/clpbackup/clpbackup.conf config
/etc/clpbackup/excludes.txt excludes; excludes.d/<domain>.txt per site
/etc/clpbackup/local.pass, offsite.pass repository passwords (also in your password manager!)
/etc/clpbackup/my.cnf MariaDB access
/var/backups/clpbackup/repo local restic repository
/var/backups/clpbackup/restore/ extracted restores (clean up manually)
/var/log/clpbackup/clpbackup.log log
Testing
tests/run-docker-tests.sh builds an Ubuntu 24.04 container with MariaDB, nginx, PHP-FPM, an SFTP
server as offsite target and an emulated CloudPanel (database schema and a clpctl mock), and runs
one end-to-end scenario: install, backups, excludes, retention, all restore variants including a
deleted site, error handling and shellcheck. Things that cannot be tested in Docker (real clpctl,
systemd timers, real mail, your offsite provider) should be verified on a test site on your server.
Disclaimer
This software comes without any warranty (see LICENSE). Backups are only as good as your last successful restore: test your restores, keep your repository passwords safe, and monitor the notifications. clpbackup is not affiliated with CloudPanel.
License
MIT — see LICENSE.