Object storage backups for cPanel and VPS can keep a recovery copy outside the source server’s failure domain. This guide uses rclone to copy completed account archives, restic for encrypted incremental file backups and cron for scheduling. Examples require a Linux root Bash shell; per-account hosting permissions are covered separately. Select a supported S3-compatible target outside the source failure domain, whether your VPS or dedicated server is hosted by DCHost or another provider.
If you already understand why backups are important, your next question is usually: “How do I automate this in a clean, testable way while monitoring jobs and checking restores?” That is exactly what we will cover: what to back up on cPanel/VPS, how to structure your object storage buckets, how to configure rclone and restic securely, how to schedule jobs with Cron, and how to test restores so you know the whole chain really works.
Why Off‑Site Backups to Object Storage Matter
Modern backup strategy is no longer just “copy files to another folder”. Between ransomware, accidental deletions, hardware failures and region‑wide incidents, you need a design that survives multiple failure modes. The classic pattern for this is the 3‑2‑1 backup strategy: three copies of your data, on two different media, with one copy off‑site. If this sounds new to you, we recommend reading our detailed guide explaining the 3‑2‑1 backup strategy and how to automate it on cPanel and VPS.
S3‑compatible object storage can serve as the off‑site part of 3‑2‑1 when it is independent of the source server’s location:
- Durability: Verify the service’s replication and failure domains. A single-node deployment does not provide multi-region protection.
- Costs: Include capacity, API requests, verification reads, restores and minimum charges.
- Automation: rclone and restic support S3 backends; verify the selected endpoint and permissions.
- Location: An independent region can reduce shared failures; residency and legal requirements need separate assessment.
If you want a broader comparison of storage types, we also have a detailed article on Object Storage vs Block Storage vs File Storage and which one to choose for web apps and backups.
Architecture: cPanel/VPS + Object Storage + rclone + restic + Cron
Before writing any scripts, it helps to be clear on the overall architecture. For a typical cPanel or generic Linux VPS server, a clean design looks like this:
- Source server: cPanel server or unmanaged VPS where your sites, databases and emails live.
- Local backup staging: a directory on the same server (for example
/backupor/var/backups) where we generate daily backups or cPanel account archives. - restic repository: an encrypted backup repository stored directly in S3‑compatible object storage.
- rclone remote: a configured connection to your S3‑compatible storage endpoint.
- Cron jobs: scheduled tasks that run backup scripts (files + databases) and send them to the restic repository via S3.
There are two main patterns you can combine:
- Native cPanel archives + rclone: Produce completed compressed account archives and copy each to a unique remote prefix. Encryption and archive retention are separate from the restic workflow.
- restic directly to S3: Back up selected files and completed SQL dumps. File-level history is not a replacement for cPanel account metadata or a server rebuild plan.
You can use both patterns: preserve native cPanel restore points and also maintain a restic repository for quick granular restores. Our other article on off‑site backups with restic/Borg to S3‑compatible storage goes deeper into the theory; here we will focus more on concrete scripts for cPanel/VPS. Automated full-account restoration is performed through WHM by an authorized administrator or hosting provider. The cPanel Backup interface can restore appropriate partial backups; manually extracting public_html files from a full archive does not restore the whole account. Confirm the required access and full restoration procedure before relying on this backup path.
Preparing Your Object Storage Target
First, you need an S3‑compatible object storage endpoint and credentials. This could be:
- A third-party S3-compatible service whose supported endpoint and permissions you verify.
- A self-managed deployment in a separate failure domain; availability depends on its nodes, disks and operations. Our MinIO deployment guide discusses architecture; a single node is not equivalent to multi-region redundancy.
Create a dedicated bucket for backups, for example:
- Example bucket:
company-backups. - Keep independent archive and repository prefixes:
cpanel/server01/account/run-id,restic-vpsandrestic-cpanel. - Do not age-expire objects inside restic repositories: old data can still be referenced by current snapshots. Archive lifecycle rules require a separate retention/recovery plan.
Then create an access key and secret key for a user that has permissions restricted to that bucket only (least privilege). Keep these credentials safe; we will store them in a root‑only configuration file or in environment variables on the server.
Installing and Configuring rclone for S3‑Compatible Storage
rclone is a versatile command‑line tool that can sync files and directories to many cloud backends, including S3‑compatible services supported by its S3 backend.
Install rclone on a Linux VPS or cPanel server
Use a suitable package from your distribution’s supported repositories. For Debian/Ubuntu, for example:
sudo apt update
sudo apt install rclone
On AlmaLinux/Rocky/other RHEL derivatives, if rclone is available in your enabled repositories:
sudo dnf install rclone
An alternative is the official release archive. The following Linux amd64 version and SHA-256 were checked on 4 November 2026. Use an empty working directory with curl, unzip, bzip2 and sha256sum. Other versions or CPU architectures need their own matching package and checksum; changing only the version variable is insufficient.
(
set -euo pipefail
rclone_version=1.75.2
curl -fLO "https://downloads.rclone.org/v${rclone_version}/rclone-v${rclone_version}-linux-amd64.zip"
printf '%s %s\n' '349ac8fba6ff65d6247043f1750cdcb518ec5d500ef91463a10d37c0ccdf3702' \
"rclone-v${rclone_version}-linux-amd64.zip" | sha256sum -c -
unzip "rclone-v${rclone_version}-linux-amd64.zip"
install -m 755 "rclone-v${rclone_version}-linux-amd64/rclone" /usr/local/bin/rclone
/usr/local/bin/rclone version
)
Configure an S3 remote in rclone
Run the configuration wizard as root:
sudo rclone config
Follow the interactive prompts:
- Name the remote
backup-s3and choose storage types3. - Select the listed provider, or
Otherfor a generic S3-compatible service. - Set endpoint, region, authentication, ACL and storage class according to provider documentation.
https://objects.example.comis a placeholder. - The bucket belongs in command paths such as
backup-s3:company-backups/cpanel; do not assume it is a wizard setting.
When done, test whether the configuration can list the bucket:
rclone lsf backup-s3:company-backups --max-depth 1
An empty bucket can return no output with exit status 0. This does not verify write/read access. Upload a small file to a separate test prefix and compare it with rclone check --download. Protect the actual config path shown by rclone config file with root ownership and mode 600.
Setting Up Restic Repositories for Encrypted, Deduplicated Backups
restic is a modern backup program that offers encrypted, incremental, deduplicated backups and can store data directly in S3‑compatible object storage.
Install restic
On Debian/Ubuntu:
sudo apt update
sudo apt install restic
For a suitable RHEL repository package, follow your distribution’s instructions. Alternatively, the official restic 0.19.1 Linux amd64 archive below was checked on 4 November 2026; it requires decompression and a matching checksum. The later scripts also require Bash, flock, gzip and jq in cron’s PATH.
(
set -euo pipefail
restic_version=0.19.1
curl -fLO "https://github.com/restic/restic/releases/download/v${restic_version}/restic_${restic_version}_linux_amd64.bz2"
printf '%s %s\n' 'f415415624dcc452f2a02b8c33641791a8c6d6d3b65bbb3543fcf9a25151585c' \
"restic_${restic_version}_linux_amd64.bz2" | sha256sum -c -
bzip2 -dk "restic_${restic_version}_linux_amd64.bz2"
install -m 755 "restic_${restic_version}_linux_amd64" /usr/local/bin/restic
/usr/local/bin/restic version
)
Environment variables for restic + S3
Use separate protected files: /root/restic-vps.env and /root/restic-cpanel.env. Create the VPS file below with root ownership and mode 600, replace every placeholder and create a separate mode-600 password file containing the real strong repository password. Keep its secure recovery copy outside this server. Do not overwrite an existing environment/password file when adding another workflow.
export RESTIC_REPOSITORY='s3:https://objects.example.com/company-backups/restic-vps'
export RESTIC_PASSWORD_FILE='/root/restic-vps.password'
export AWS_ACCESS_KEY_ID='REPLACE_WITH_ACCESS_KEY'
export AWS_SECRET_ACCESS_KEY='REPLACE_WITH_SECRET_KEY'
export BACKUP_HOST='server01'
Secure the file:
chown root:root /root/restic-vps.env /root/restic-vps.password
chmod 600 /root/restic-vps.env /root/restic-vps.password
Initialize the restic repository
Run the following commands in a root Bash shell, with the environment variables loaded from the protected file, to initialize the repository:
source /root/restic-vps.env
restic init
Run init only once for the intended new repository. For an existing repository, verify access using restic snapshots. Losing the password can make intact backup objects unrecoverable. AWS-prefixed environment variable names are also used with supported non-AWS S3 endpoints.
Example Backup Flow for a cPanel Server
On cPanel/WHM, you usually want two layers:
- cPanel's native backups (account‑level archives for easy full account restores).
- Optionally, a restic layer for deduplicated, long‑retention backups across many days or weeks.
1. Enable and tune native cPanel backups
In WHM, go to Backup Configuration and:
- Enable backups and choose the documented mode for your recovery plan. This article’s transport path uses compressed account archives.
- Set an appropriate local directory and retention; verify the supported additional destinations for the chosen cPanel mode.
- Incremental raw directory trees copied to S3 do not by themselves demonstrate full account restoration with metadata.
- A full archive may omit settings such as account 2FA; verify source/target version compatibility and document required reconfiguration.
If you want a detailed walkthrough of cPanel backup options, see our Full cPanel Backup and Restore guide.
2. Produce, Verify and Copy a cPanel Account Archive
The root-only example below waits for pkgacct in the same job. It does not infer completion from a later clock time. First prepare staging directories; create /root/cpanel-archive.env as root:root/600 with the settings shown. Save the script as /opt/backups/cpanel-backup.sh. Official pkgacct guidance requires free space exceeding twice the largest account plus an additional 1 GB on both source and destination; allow more for retained runs and logs.
umask 077
install -d -m 700 /opt/backups /opt/backups/db-dumps /opt/backups/status /opt/backups/cpanel
ARCHIVE_REMOTE='backup-s3:company-backups/cpanel'
BACKUP_HOST='server01'
#!/usr/bin/env bash
set -euo pipefail
umask 077
export PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin
account=${1:?Usage: cpanel-backup.sh CPANEL_ACCOUNT}
[[ "$account" =~ ^[a-z][a-z0-9_]{0,15}$ ]] || exit 64
[[ -f "/var/cpanel/users/$account" ]] || exit 66
source /root/cpanel-archive.env
: "${ARCHIVE_REMOTE:?}" "${BACKUP_HOST:?}"
[[ "$BACKUP_HOST" =~ ^[A-Za-z0-9._-]+$ ]] || exit 64
exec 9>/opt/backups/.backup.lock
flock -n 9 || { printf 'Backup lock is busy.\n' >&2; exit 75; }
install -d -m 700 /opt/backups/cpanel /opt/backups/status
work=$(mktemp -d /opt/backups/cpanel/.run.XXXXXX)
trap 'printf "Local run directory retained: %s\n" "$work" >&2' EXIT
install -d -m 700 "$work/package" "$work/ready"
/usr/local/cpanel/scripts/pkgacct --backup --dbbackup=all \
"$account" "$work/package" > "$work/pkgacct.log" 2>&1
if ! grep -qF 'pkgacct completed' "$work/pkgacct.log"; then
printf 'No successful pkgacct completion marker; inspect %s\n' "$work/pkgacct.log" >&2
exit 65
fi
archive="$work/package/$account.tar.gz"
[[ -s "$archive" ]] || exit 66
gzip -t "$archive"
mv -- "$archive" "$work/ready/$account.tar.gz"
run_id="$(date -u +%Y%m%dT%H%M%SZ)-${work##*.}"
destination="${ARCHIVE_REMOTE%/}/$BACKUP_HOST/$account/$run_id"
rclone copy "$work/ready" "$destination" --immutable \
--transfers=1 --checkers=2 --bwlimit=5M
rclone check "$work/ready" "$destination" --download --one-way
state=$(mktemp /opt/backups/status/.cpanel-state.XXXXXX)
printf '%s %s\n' "$(date -u +%FT%TZ)" "$destination" > "$state"
mv -f -- "$state" "/opt/backups/status/cpanel-$account-last-success"
printf 'Verified archive destination: %s\n' "$destination"
Make it executable:
chown root:root /opt/backups/cpanel-backup.sh
chmod 700 /opt/backups/cpanel-backup.sh
Test the script manually with a real account name before scheduling and verify the pkgacct completion marker on your installed cPanel version. It retains local run directories and logs on both success and failure: define a separate cleanup policy after remote verification and monitor disk capacity. copy preserves destination-only files; --immutable rejects changed existing files. sync and --delete-excluded can remove retained copies. Read-back comparison downloads data and can incur charges. The local flock only coordinates cooperating jobs on this host; avoid overlap with independent WHM schedulers and other writers.
3. Optional: restic layer for deduplicated history
For optional file-level history, use /root/restic-cpanel.env, a separate repository and password file. This layer backs up selected live paths and completed dumps; it does not replace native full account archives. Deduplication savings depend on actual data.
export RESTIC_REPOSITORY='s3:https://objects.example.com/company-backups/restic-cpanel'
export RESTIC_PASSWORD_FILE='/root/restic-cpanel.password'
export AWS_ACCESS_KEY_ID='REPLACE_WITH_ACCESS_KEY'
export AWS_SECRET_ACCESS_KEY='REPLACE_WITH_SECRET_KEY'
export BACKUP_HOST='server01'
Replace placeholders, create /root/restic-cpanel.password, and protect both files as root:root/600. Keep an off-server recovery copy of the password. Initialize this new repository once:
source /root/restic-cpanel.env
restic init
Save the following as /opt/backups/restic-cpanel-backup.sh, root:root/700. It requires the database helper and configuration in the next section before it can run. Select the databases for these accounts explicitly; do not assume the example list covers every account.
#!/usr/bin/env bash
set -euo pipefail
umask 077
export PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin
exec 9>/opt/backups/.backup.lock
flock -n 9 || { printf 'Backup lock is busy.\n' >&2; exit 75; }
source /root/restic-cpanel.env
source /opt/backups/db-dump.sh
: "${BACKUP_HOST:?}"
[[ -d /home && -d /etc && -d /var/named ]] || exit 66
install -d -m 700 /opt/backups/status
result=$(mktemp /opt/backups/status/.cpanel-files-result.XXXXXX)
state=$(mktemp /opt/backups/status/.cpanel-files-state.XXXXXX)
trap 'rm -f -- "$result" "$state"' EXIT
make_database_dump
restic backup /home /etc /var/named /opt/backups/db-dumps/databases.sql.gz \
--host "$BACKUP_HOST" --tag cpanel-files --json > "$result"
snapshot_id=$(jq -er 'select(.message_type == "summary") | .snapshot_id' "$result")
[[ "$snapshot_id" =~ ^[0-9a-f]{64}$ ]] || exit 65
printf '%s %s\n' "$(date -u +%FT%TZ)" "$snapshot_id" > "$state"
mv -f -- "$state" /opt/backups/status/cpanel-files-last-success
cat "$result"
The job covers /home, /etc, /var/named and the completed dump file. Inventory real paths, nested mounts and symlink targets before using it: restic stores symlinks without following them. Live files and SQL are not automatically one application-consistent point; coordinate writes or use an application-appropriate snapshot process. A nonzero restic result, including partial-backup code 3, does not update the last-success record.
Example Backup Flow for a Generic VPS (Without cPanel)
On an unmanaged VPS (for example hosting a Laravel or Node.js app), you usually control everything via SSH. Here is an example pattern to adapt to your application.
1. Define what to back up
For a typical Linux VPS running web applications, you want:
- Application code and uploads: for example
/var/wwwor/opt/apps. - Databases: MySQL/MariaDB, PostgreSQL, etc. Usually via logical dumps or snapshot tools.
- Configuration:
/etc(web server, PHP‑FPM, system config). - Optional logs: at least for short retention, if you need to investigate incidents.
We have a separate article on MySQL backup strategies (mysqldump vs XtraBackup vs snapshots) if you want to design your database backup layer in more detail.
2. Example: MySQL dump + restic
Create /opt/backups/db-dump.sh with the function below. The main locked job sources it; do not schedule it independently. Configure /root/backup-database.env with mysql or mariadb and explicit application database names. /root/backup-mysql.cnf supplies supported authentication. Protect both files with root ownership and mode 600; test permissions for selected tables, views, routines, events and triggers.
umask 077
install -d -m 700 /opt/backups /opt/backups/db-dumps /opt/backups/status /opt/backups/cpanel
The database-name validation accepts letters, digits and underscores only; adapt it deliberately for other naming schemes. A raw MySQL data directory is not equivalent to a completed logical dump.
DB_FLAVOR=mysql
DB_DEFAULTS_FILE=/root/backup-mysql.cnf
DB_NAMES=(application_db)
[client]
user=backup_user
password=REPLACE_WITH_DATABASE_PASSWORD
#!/usr/bin/env bash
# Source this file from a backup job holding /opt/backups/.backup.lock.
make_database_dump() (
set -euo pipefail
umask 077
source /root/backup-database.env
: "${DB_FLAVOR:?}" "${DB_DEFAULTS_FILE:?}"
(( ${#DB_NAMES[@]} > 0 )) || exit 64
[[ -r "$DB_DEFAULTS_FILE" ]] || exit 66
for database in "${DB_NAMES[@]}"; do
[[ "$database" =~ ^[A-Za-z0-9_]+$ ]] || exit 64
done
case "$DB_FLAVOR" in
mysql) dump_command=mysqldump; extra=(--set-gtid-purged=OFF) ;;
mariadb) dump_command=mariadb-dump; extra=() ;;
*) printf 'Set DB_FLAVOR to mysql or mariadb.\n' >&2; exit 64 ;;
esac
dump_dir=/opt/backups/db-dumps
install -d -m 700 "$dump_dir"
partial=$(mktemp "$dump_dir/.databases.sql.gz.XXXXXX")
trap 'rm -f -- "$partial"' EXIT
"$dump_command" --defaults-extra-file="$DB_DEFAULTS_FILE" \
--single-transaction --quick --routines --events --triggers \
--no-tablespaces "${extra[@]}" --databases "${DB_NAMES[@]}" \
| gzip > "$partial"
gzip -t "$partial"
mv -f -- "$partial" "$dump_dir/databases.sql.gz"
)
--single-transaction provides consistency for transactional tables such as InnoDB; MyISAM/MEMORY tables can change during the dump. Do not run ALTER/CREATE/DROP/RENAME/TRUNCATE while it runs. The MySQL branch disables GTID transfer and is not a replication/PITR setup; the MariaDB branch uses its own client. This application dump omits unselected databases, account grants, general tablespace definitions and other server metadata. PostgreSQL and physical-backup tools require their own coordinated workflow. The helper keeps the previous completed dump if generation fails and removes its private partial file.
chown root:root /opt/backups/db-dump.sh
chmod 600 /opt/backups/db-dump.sh
For the generic VPS job, use the /root/restic-vps.env prepared earlier. The following is the same configuration, not a new repository to initialize over existing state. Adapt source paths and authentication to the actual application, protect its password file and preserve its off-server recovery copy:
export RESTIC_REPOSITORY='s3:https://objects.example.com/company-backups/restic-vps'
export RESTIC_PASSWORD_FILE='/root/restic-vps.password'
export AWS_ACCESS_KEY_ID='REPLACE_WITH_ACCESS_KEY'
export AWS_SECRET_ACCESS_KEY='REPLACE_WITH_SECRET_KEY'
export BACKUP_HOST='server01'
If this new VPS repository has not already been initialized, run the following once. Otherwise use restic snapshots to verify it:
source /root/restic-vps.env
restic init
Save the main job as /opt/backups/restic-backup.sh. It takes the shared local lock, creates the dump and backs up /var/www, /etc and only the completed SQL archive. It records the full snapshot ID and UTC completion time only after success:
#!/usr/bin/env bash
set -euo pipefail
umask 077
export PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin
exec 9>/opt/backups/.backup.lock
flock -n 9 || { printf 'Backup lock is busy.\n' >&2; exit 75; }
source /root/restic-vps.env
source /opt/backups/db-dump.sh
: "${BACKUP_HOST:?}"
[[ -d /var/www && -d /etc ]] || exit 66
install -d -m 700 /opt/backups/status
result=$(mktemp /opt/backups/status/.vps-result.XXXXXX)
state=$(mktemp /opt/backups/status/.vps-state.XXXXXX)
trap 'rm -f -- "$result" "$state"' EXIT
make_database_dump
restic backup /var/www /etc /opt/backups/db-dumps/databases.sql.gz \
--host "$BACKUP_HOST" --tag vps-app --json > "$result"
snapshot_id=$(jq -er 'select(.message_type == "summary") | .snapshot_id' "$result")
[[ "$snapshot_id" =~ ^[0-9a-f]{64}$ ]] || exit 65
printf '%s %s\n' "$(date -u +%FT%TZ)" "$snapshot_id" > "$state"
mv -f -- "$state" /opt/backups/status/vps-last-success
cat "$result"
Make it executable:
chown root:root /opt/backups/restic-backup.sh
chmod 700 /opt/backups/restic-backup.sh
Scheduling and Monitoring with Cron
Once your scripts work when run manually, the next step is automation with Cron. We have a separate guide on automating backups, reports and maintenance with Cron on cPanel and DirectAdmin, but we will highlight the essentials here.
Scheduling on a generic Linux VPS
Edit the root user's crontab:
sudo crontab -e
Install only your chosen workflows, after a successful manual run and restore test. These times use the server cron time zone; measure completion duration and choose intervals from your RPO. Local lock contention exits 75 and skips that run, so monitor missing success as well as errors. Do not overlap independent WHM jobs or other hosts writing the same repository.
# Replace CPANEL_ACCOUNT with the real account name.
0 3 * * * /opt/backups/cpanel-backup.sh CPANEL_ACCOUNT >> /var/log/cpanel-backup.log 2>&1
# VPS example: every four hours.
0 */4 * * * /opt/backups/restic-backup.sh >> /var/log/restic-backup.log 2>&1
# Optional cPanel file history; choose a nonconflicting schedule.
30 4 * * * /opt/backups/restic-cpanel-backup.sh >> /var/log/restic-cpanel-backup.log 2>&1
Cron can email output that a job leaves on standard output or standard error when mail delivery is configured. These backup scripts redirect their main output, including errors, to log files, so cron mail alone will not report those failures. Monitor exit status and alert when no successful backup completes within the expected interval. In addition, you can:
- Monitor
/var/log/cpanel-backup.log,/var/log/restic-backup.logand, if enabled,/var/log/restic-cpanel-backup.log. - Push log metrics into your existing monitoring stack (for example Prometheus + alerting), similar to what we describe in our article on VPS monitoring and alerts with Prometheus and Grafana.
Scheduling from cPanel/WHM
On cPanel servers, you can also schedule scripts using:
- Root system jobs: use the root user’s crontab for these /root and /opt/backups scripts.
- WHM Configure cPanel Cron Jobs: controls upcp, backup and cpbackup schedules; it is not a generic arbitrary-root-script UI.
- cPanel Cron Jobs: per-account jobs are limited to that account’s permissions, binaries, quotas and readable paths.
A shared-hosting account cannot simply run the root examples. Confirm allowed tools and quotas with the provider, obtain a completed account archive through the supported workflow and agree the full restoration path. A cPanel partial restore is a different operation from an authorized WHM full-account restore.
Testing Restores: Don’t Wait for an Incident
A backup that has never been restored is an assumption, not a guarantee. We strongly recommend including regular restore tests in your maintenance schedule. This is also a key part of any serious disaster recovery plan; if you are designing one, our guide on how to write a disaster recovery (DR) plan with realistic RPO/RTO and backup tests may help.
Testing restic restores
List snapshots:
source /root/restic-vps.env
restic snapshots --host "$BACKUP_HOST" --tag vps-app
Select an explicitly recorded successful snapshot ID. The following restores the entire chosen snapshot into a new private directory; it does not select only one website:
(
set -euo pipefail
umask 077
source /root/restic-vps.env
restic snapshots --host "$BACKUP_HOST" --tag vps-app
read -r completed_at snapshot_id < /opt/backups/status/vps-last-success
[[ "$snapshot_id" =~ ^[0-9a-f]{64}$ ]] || exit 65
restore_dir=$(mktemp -d /opt/backups/restore.XXXXXX)
chmod 700 "$restore_dir"
restic restore "$snapshot_id" --target "$restore_dir"
printf 'Restore directory: %s\n' "$restore_dir"
)
Check bytes, ownership, permissions, symlinks and application behavior. For selected files, inspect paths using restic ls SNAPSHOT_ID and then use --include; --path selects snapshots rather than filtering restored files. If the source server is lost, obtain the explicit ID from off-server runbook records and snapshot listings. Review CREATE DATABASE/USE statements before importing SQL with a compatible client on an isolated test server; MariaDB dump sandbox statements may fail in older MariaDB or MySQL clients. Disable real mail, payment and webhook integrations during tests.
Testing cPanel restores
For cPanel native backups:
- Download the selected complete archive to a private directory using rclone.
- Use WHM’s supported full-backup/cpmove restoration process through an authorized administrator or provider on a separate test server.
- Validate account files, databases, mail, DNS/SSL and required reconfiguration. cPanel partial restoration or extracting public_html does not recreate the whole account.
A successful gzip or transfer check is not proof of application recovery. Verify the actual items required by your account and version; for example, pkgacct documentation excludes transferred 2FA configuration. Record recovery time and the recovered data point against your RTO/RPO.
Hardening, Cost Control and Practical Tips
Use these checks when adapting the examples to your workload; service capabilities and recovery results must be verified in your environment.
1. Protect credentials and limit access
- Store S3 access keys in root‑owned files with
chmod 600, never in world‑readable scripts. - Create a dedicated S3 user with bucket‑scoped permissions (no access to other buckets or admin APIs).
- Rotate access keys periodically and test after rotation.
2. Use encryption correctly
- Restic encrypts repository content client-side. Protect the password file and keep a separate recovery copy; encryption does not prevent a compromised client from exposing plaintext or deleting accessible backups.
- For plain rclone archives,
cryptcan provide client-side encryption; test both its configuration and key recovery. - Versioning and Object Lock may add protection where supported, but storage locking, restic lock-object deletion and prune must be tested together. The S3 Object Lock and recovery guide discusses those controls; no tool combination guarantees immunity.
3. Exclude junk and temporary data
Backups are not a trash bag for everything on the disk. Excluding some paths improves speed and reduces costs:
- Cache directories (for example
storage/framework/cachein Laravel,wp-content/cachein WordPress). - System caches under
/var/cachethat can be rebuilt. - Big application logs if you already centralize logs elsewhere (for example Loki/ELK stack).
Use explicit --exclude or --exclude-file rules only after checking recovery requirements. --exclude-caches recognizes CACHEDIR.TAG; it does not mean all application caches. --one-file-system can omit nested mounts and subvolumes, so the examples do not add it silently. List required filesystem roots explicitly if you choose that option.
4. Watch bandwidth and storage costs
- Measure production load and choose off-peak periods, transfer limits and, where effective, nice/ionice priorities.
- Deduplication savings depend on repeated data; compressed/encrypted dump changes can reduce reuse. Estimate costs using a pilot, including API operations, read-back verification and restores.
- Choose retention from recovery and legal requirements, as discussed in our backup retention guide. Keep policy separate from the daily job.
Save the following as /opt/backups/restic-maintenance.sh, root:root/700. Preview first. The explicit apply mode deletes expired snapshots and prunes unused data. The 7-day window is relative to each group’s newest snapshot and keeps intraday points; daily/weekly/monthly rules combine rather than adding to a guaranteed fixed count. Changing host, source paths or tags can create another group.
#!/usr/bin/env bash
set -euo pipefail
umask 077
export PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin
case "${1:-}" in
vps) source /root/restic-vps.env; backup_tag=vps-app ;;
cpanel) source /root/restic-cpanel.env; backup_tag=cpanel-files ;;
*) printf 'Usage: restic-maintenance.sh vps|cpanel [apply]\n' >&2; exit 64 ;;
esac
: "${BACKUP_HOST:?}"
exec 9>/opt/backups/.backup.lock
flock -n 9 || { printf 'Backup lock is busy.\n' >&2; exit 75; }
policy=(--host "$BACKUP_HOST" --tag "$backup_tag" --group-by host,paths,tags
--keep-within 7d --keep-daily 7 --keep-weekly 4 --keep-monthly 6)
case "${2:-preview}" in
preview) restic forget "${policy[@]}" --dry-run ;;
apply) restic forget "${policy[@]}" --prune ;;
*) exit 64 ;;
esac
/opt/backups/restic-maintenance.sh vps
# Review first; this next command deletes expired snapshots:
/opt/backups/restic-maintenance.sh vps apply
Use cpanel for the separate cPanel repository. Coordinate other hosts as prune needs an exclusive repository lock. Do not expire restic objects by age using S3 lifecycle rules or move live repository objects to an inaccessible archive class. Run periodic restic check; schedule restic check --read-data when you can afford downloading all packs, because the default check does not read all data. Retention counts do not increase backup frequency.
5. Integrate with monitoring and runbooks
- Monitor last-success age and command failures, including skipped lock-conflict runs.
- Keep successful full snapshot IDs and archive destinations in an off-server monitoring/runbook record; a local marker can be lost with the server.
- Test alert delivery and rehearse site, database and account recovery using a written runbook.
Bringing It All Together on dchost.com Infrastructure
The pattern applies to cPanel, VPS, dedicated and colocation workloads hosted by DCHost or another provider: define source scope, generate completed recoverable data, store an independent copy, monitor automation and rehearse restoration. Do not assume an included backup service or a particular Object Storage endpoint; confirm your service’s scope and permissions.
If you are starting from scratch, your practical next steps are:
- Choose or deploy an S3‑compatible object storage backend and create a dedicated backup bucket.
- Install and configure rclone and restic on your cPanel/VPS servers.
- Write minimal backup scripts that you can run manually and verify.
- Add Cron schedules and basic monitoring for success/failure.
- Plan and rehearse at least one restore scenario (single site, full server, or critical database).
Scale the tested workflow after measuring backup duration, storage growth and restore time. Add regional copies, versioning or object locking only after validating their operational and recovery requirements. Encryption and location choices alone do not establish KVKK/GDPR compliance; retention, access, deletion and applicable obligations need their own assessment.





