JetBackup 5 introduces multi-panel support, meaning that backups can be created in a cPanel server, for example, can be restored on a DirectAdmin server (and vice versa).
To achieve that, the JetBackup team has to create its own unique backup structure (Unlike JetBackup v4 which was based on the cPanel backups structure).
Here is a “Quick & Dirty” bash magic script that will convert a JetBackup 5 structure into cPanel backup structure (“cpmove file”), the generated cPmove file can be restored on any cPanel server (/scripts/restorepkg) regardless of JetBackup (doesn’t have to be installed on the server).
The script can generate a cPanel backup from an already downloaded backup file (usually located at /usr/local/jetapps/usr/jetbackup5/downloads), or you can provide a username, and it will fetch the latest backup automatically (given that there are full active backups for that account).
RAW version: https://thelazyadmin.blog/scripts/jb5_to_cpanel_convertor.txt
Quick Download
wget https://thelazyadmin.blog/scripts/jb5_to_cpanel_convertor.txt -O /root/jb5_to_cpanel_convertor.sh chmod +x /root/jb5_to_cpanel_convertor.sh cd /root ./jb5_to_cpanel_convertor.sh
Full Script
#!/bin/bash # Convert the supplied JetBackup 5 backup file to a cPanel-compatible backup. # # Originally created by TheLazyAdmin, https://thelazyadmin.blog # # ** USE AT YOUR OWN RISK ** # MIT License # # Copyright (c) 2022 TheLazyAdmin # Copyright (c) 2023,2024 Christopher Handley # # Permission is hereby granted, free of charge, to any person obtaining a copy # of this software and associated documentation files (the "Software"), to deal # in the Software without restriction, including without limitation the rights # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell # copies of the Software, and to permit persons to whom the Software is # furnished to do so, subject to the following conditions: # # The above copyright notice and this permission notice shall be included in all # copies or substantial portions of the Software. # # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE # SOFTWARE. function Error { echo "" echo "$1" exit 1 } function ErrorHelp { echo "" echo "$1" echo " How to use: jb5_to_cpanel_convertor.sh JETBACKUP5_BACKUP [DESTINATION_FOLDER] JETBACKUP5_BACKUP = Source JetBackup file DESTINATION_FOLDER = Optional destination folder for cPanel backup, defaults to /home/, if you are root, otherwise to ~/ e.g. jb5_to_cpanel_convertor.sh /home/download_jb5user_1663238955_28117.tar.gz " exit 1 } function Untar() { BackupPath="$1" DestPath="$2" tar -xf "$BackupPath" -C "$DestPath" Err=$? [[ $Err -gt 0 ]] && Error "Unable to untar the file '$BackupPath'" } function Extract() { FilePath="$1" gunzip $FilePath # FilePath not quoted so can expand wildcard Err=$? [[ $Err -gt 0 ]] && Error "Unable to extract files" } function MoveDir() { Src="$1" Dst="$2" echo "Converting folder '$Src'" # Fixed an issue where the Dst directory did not exist, causing problems with MySQL DB/DB user conversion mkdir -p "$Dst" mv $Src "$Dst" # Src not quoted so can expand wildcard Err=$? [[ $Err -gt 0 ]] && Error "An error occurred" } function Archive() { TarName="$1" echo "Creating archive '$DestDir/$TarName'" if [ -f "$DestDir/$TarName" ]; then rm "$DestDir/$TarName"; fi # Ensure create a new archive from scratch cd "$UnzipDest" || Error "Failed to CD to '$UnzipDest'" tar -czf "$DestDir/$TarName" "cpmove-$AccountName" >/dev/null 2>&1 Err=$? [[ $Err != 0 ]] && Error "Unable to create tar file" } function CreateFTPaccount() { DirPath="$1" ConfigPath="$2" HomeDir="$( cat "$ConfigPath/meta/homedir_paths" )" User="$( ls "$ConfigPath/cp/")" for FILE in "$DirPath"/*.acct; do [ -f "$FILE" ] || continue Username="$(grep -Po '(?<=name: )(\w\D+)' "$FILE")" Password="$(grep -Po '(?<=password: )([A-Za-z0-9!@#$%^&*,()\/\\.])+' "$FILE")" WebRootPath="$(grep -Po '(?<=path: )([A-Za-z0-9\/_.-]+)' "$FILE")" echo "Creating FTP account '$Username'"; printf "%s:%s:0:0:%s:%s/%s:/bin/ftpsh" "$Username" "$Password" "$User" "$HomeDir" "$WebRootPath" >> "$CPanelDir/proftpdpasswd" done } function CreateMySQLfile() { DirPath="$1" SQL_FilePath="$2" for FILE in "$DirPath"/*.user; do [ -f "$FILE" ] || continue Username="$(grep -Po '(?<=name: )([a-zA-Z0-9!@#$%^&*(\)\_\.-]+)' "$FILE")" Database="$(grep -Po '(?<=database `)([_a-zA-Z0-9]+)' "$FILE")" User="$(grep -Po '(?<=name: )([a-zA-Z0-9!#$%^&*(\)\_\.]+)' "$FILE")" Domain="$(echo "$Username" | grep -Po '(?<=@)(.*)$')" Password="$(grep -Po '(?<=password: )([a-zA-Z0-9*]+)' "$FILE")" Permissions="$(grep -Po '(?<=:)[A-Z ,]+$' "$FILE")" echo "Creating DB '$Database' & adding DB user '$User'" echo "GRANT USAGE ON *.* TO '$User'@'$Domain' IDENTIFIED BY PASSWORD '$Password';" >> "$SQL_FilePath" echo "GRANT$Permissions ON \`$Database\`.* TO '$User'@'$Domain';" >> "$SQL_FilePath" done } function CreateEmailAccount() { BackupEmailPath="$1" DestEmailPath="$2" echo "Creating email accounts" for JsonFile in "$BackupEmailPath"/*.conf; do [ -f "$JsonFile" ] || continue MailUser="$(jq -r '.account' "$JsonFile" | base64 --decode)" MailDomain="$(jq -r '.domain' "$JsonFile" | base64 --decode)" MailPassword="$(jq -r '.password' "$JsonFile" | base64 --decode)" if [ -z "$MailUser" ] || [ -z "$MailDomain" ]; then echo " Skipping email account in '$(basename "$JsonFile")' (missing account or domain)" continue fi # Ensure the per-domain mail dir exists before appending credentials, # otherwise the redirect below fails silently and the password is lost mkdir -p "$DestEmailPath/${MailDomain}" echo "${MailUser}:${MailPassword}:::::::" >>"$DestEmailPath/${MailDomain}/shadow" done } function CreateDomains() { DirPath="$1" ConfigPath="$2" echo "Creating domains" # find primary domain PrimaryDomain="" for JSON_FILE in "$DirPath"/*.conf; do Domain="$(jq -r '.domain' "$JSON_FILE" | base64 --decode)" Type="$(jq -r '.type' "$JSON_FILE" | base64 --decode)" if [ "$Type" = "1" ]; then PrimaryDomain="$Domain" fi done if [ -z "$PrimaryDomain" ]; then Error "Failed to find the primary domain of account '$AccountName'"; fi # OR COULD JUST DO: PrimaryDomain="$( cat "$CPanelDir/cp/$AccountName" | grep -Po '(?<=DNS=)([A-Za-z0-9-.]+)')" # write info about sub-domains of the primary domain echo -n "" >"$ConfigPath"/sds echo -n "" >"$ConfigPath"/sds2 for JSON_FILE in "$DirPath"/*.conf; do #WebRoot="$(jq -r '.public_dir' "$JSON_FILE" | base64 --decode)" Domain="$(jq -r '.domain' "$JSON_FILE" | base64 --decode)" Type="$(jq -r '.type' "$JSON_FILE" | base64 --decode)" if [[ "$Type" == "3" && "$Domain" == *.$PrimaryDomain ]]; then # (sub-domain) echo " Adding sub-domain '$Domain'" echo "${Domain/./_}" >>"$ConfigPath"/sds echo "${Domain/./_}=$Domain" >>"$ConfigPath"/sds2 fi done # write info about addon & parked domains echo -n "" >"$ConfigPath"/addons echo -n "" >"$ConfigPath"/pds for JSON_FILE in "$DirPath"/*.conf; do #WebRoot="$(jq -r '.public_dir' "$JSON_FILE" | base64 --decode)" Domain="$(jq -r '.domain' "$JSON_FILE" | base64 --decode)" Type="$(jq -r '.type' "$JSON_FILE" | base64 --decode)" if [ "$Type" = "1" ]; then # (primary domain) so ignore it : elif [ "$Type" = "2" ]; then # (addon domain) echo " Adding addon domain '$Domain'" echo "$Domain=${Domain/./_}.$PrimaryDomain" >>"$ConfigPath"/addons echo "${Domain/./_}.$PrimaryDomain" >>"$ConfigPath"/sds echo "${Domain/./_}.$PrimaryDomain=$Domain" >>"$ConfigPath"/sds2 elif [ "$Type" = "3" ]; then # (sub-domain) so ignore for the moment : elif [ "$Type" = "4" ]; then # (parked/alias domain) echo "$Domain" >>"$ConfigPath"/pds else # (unknown domain type) Error "Domain '$Domain' has unknown type '$Type'" fi done # write info about sub-domains that are NOT of the primary domain for JSON_FILE in "$DirPath"/*.conf; do #WebRoot="$(jq -r '.public_dir' "$JSON_FILE" | base64 --decode)" Domain="$(jq -r '.domain' "$JSON_FILE" | base64 --decode)" Type="$(jq -r '.type' "$JSON_FILE" | base64 --decode)" if [[ "$Type" == "3" && ! "$Domain" == *.$PrimaryDomain ]]; then # (sub-domain) echo " Adding sub-domain '$Domain'" echo "${Domain/./_}" >>"$ConfigPath"/sds echo "${Domain/./_}=$Domain" >>"$ConfigPath"/sds2 fi done } function CreateSSLcerts() { DirPath="$1" ConfigPath="$2" echo "Creating SSL certificates" # indicates the account will use WHM’s SSL Storage Manager feature (WHM » Home » SSL/TLS » SSL Storage Manager) # And without this, restoring the account will fail to install the SSL certificate, reporting "An error prevented adding a record of type “crt” ... That certificate is already installed as ..." touch "$ConfigPath"/has_sslstorage # Rebuild apache_tls/<domain> so the restore actually installs the cert on each # vhost. We derive everything from the cert/key files themselves (via openssl) # rather than from ssl.db, because ssl.db only records a 'modulus' for RSA keys -- # EC certs (and wildcard certs) cannot be matched the old modulus/commonName way. SSLDir="$ConfigPath/homedir/ssl" if ! compgen -G "$SSLDir/certs/*.crt" >/dev/null 2>&1; then echo " No SSL certificates in backup; nothing to install on vhosts" return fi if ! command -v openssl >/dev/null 2>&1; then echo " WARNING: openssl not found; skipping vhost SSL install (SSL store still carried over)" return fi mkdir -p "$ConfigPath/apache_tls" # Index private keys by their public-key fingerprint, so a key can be paired to a # cert by public key alone -- works for both RSA and EC. declare -A KeyByPub for K in "$SSLDir/keys/"*.key; do [ -f "$K" ] || continue PH="$(openssl pkey -in "$K" -pubout -outform DER 2>/dev/null | openssl dgst -sha256 2>/dev/null | awk '{print $NF}')" [ -n "$PH" ] && KeyByPub["$PH"]="$K" done # _ssl_covers CERT_DOMAIN ACCOUNT_DOMAIN -> true if the (possibly *.wildcard) # cert domain covers the account domain (wildcard matches exactly one label). _ssl_covers() { local D="$1" X="$2" Suffix Head [ "$D" = "$X" ] && return 0 if [[ "$D" == \*.* ]]; then Suffix="${D#\*.}"; Head="${X%.$Suffix}" [ "$Head.$Suffix" = "$X" ] && [ "$Head" != "$X" ] && [[ "$Head" != *.* ]] && return 0 fi return 1 } for JSON_FILE in "$DirPath"/*.conf; do [ -f "$JSON_FILE" ] || continue Domain="$(jq -r '.domain' "$JSON_FILE" | base64 --decode)" [ -z "$Domain" ] && continue # Choose the newest cert that covers this domain AND has a matching key. BestCert=""; BestKey=""; BestStart=-1 for C in "$SSLDir/certs/"*.crt; do [ -f "$C" ] || continue CertDomains="$( { openssl x509 -in "$C" -noout -ext subjectAltName 2>/dev/null | grep -oE 'DNS:[^,]+' | sed 's/DNS://; s/ //g'; openssl x509 -in "$C" -noout -subject -nameopt multiline 2>/dev/null | sed -n 's/^ *commonName *= *//p'; } )" Covered=0 for D in $CertDomains; do _ssl_covers "$D" "$Domain" && { Covered=1; break; }; done [ "$Covered" -eq 1 ] || continue # require the private key to be present CPH="$(openssl x509 -in "$C" -noout -pubkey 2>/dev/null | openssl pkey -pubin -outform DER 2>/dev/null | openssl dgst -sha256 2>/dev/null | awk '{print $NF}')" MatchKey="${KeyByPub[$CPH]}" [ -n "$MatchKey" ] || continue Start="$(openssl x509 -in "$C" -noout -startdate 2>/dev/null | sed 's/notBefore=//')" StartEpoch="$(date -d "$Start" +%s 2>/dev/null || echo 0)" if [ "$StartEpoch" -ge "$BestStart" ]; then BestStart="$StartEpoch"; BestCert="$C"; BestKey="$MatchKey"; fi done [ -n "$BestCert" ] || continue echo " Installing SSL cert for '$Domain'" # cPanel "combined" format: certificate then key. (CA bundle is omitted -- # self-signed certs have none, and cPanel can fetch a CA's bundle itself.) { cat "$BestCert"; echo ""; cat "$BestKey"; echo ""; } >"$ConfigPath/apache_tls/$Domain" done unset -f _ssl_covers } function CreateDNSZones() { DirPath="$1" ConfigPath="$2" echo "Creating DNS zones" # Fix an issue where "dnszones" directory doesn't exist, preventing copy/move. echo "Ensuring $ConfigPath DNS Zone Directory is made" mkdir -p "$ConfigPath/dnszones" for FILE in "$DirPath"/*.zone; do FileName="${FILE##*/}" DstFile="$ConfigPath/dnszones/${FileName%.*}.db" echo "ZoneFile Re-name Step - Creating '$DstFile'" mv -v "$FILE" "$DstFile" Err=$? [[ $Err -gt 0 ]] && Error "An error occurred" done } # Parse arguments FilePath="$1" DestDir="$2" # Sanity check ! [[ -f "$FilePath" ]] && ErrorHelp "Invalid file provided" [[ "$DestDir" == "/" ]] && ErrorHelp "Error :: Don't use root folder as destination" # Default arguments if [ -z "$DestDir" ]; then if [ "$(whoami)" == "root" ]; then DestDir=/home else DestDir=~ fi fi # Extract username #AccountName=$(echo "$FilePath" | grep -oP '(?<=download_)([^_]+)') AccountName="$(echo "${FilePath##*/}" | cut -d_ -f2)" [[ -z "$AccountName" ]] && ErrorHelp "Could not determine the account name from '${FilePath##*/}'. Expected a JetBackup file like download_<user>_<timestamp>_<id>.tar.gz" if [ $(( $(du --block-size=1 "$FilePath" | cut -f1)*10 )) -lt $(df --block-size=1 --output=avail /tmp | tail -n1) ]; then # (Free space of /tmp is more than 10 times the compressed archive size) so should be safe to decompress there TmpDir=/tmp elif [ $(( $(du --block-size=1 "$FilePath" | cut -f1)*2 )) -gt $(df --block-size=1 --output=avail /tmp | tail -n1) ]; then # (Free space of /tmp is less than 2 times the compressed archive size) so definitely NOT enough space TmpDir=~ else echo "/tmp may not be big enough so checking the decompressed size of the archive..." if [ $(( $(time zcat "$FilePath" | wc -c)*2 )) -lt $(df --block-size=1 --output=avail /tmp | tail -n1) ]; then # (Free space of /tmp is more than 2 times the UNcompressed archive size) so definitely safe to decompress there TmpDir=/tmp else TmpDir=~ fi fi UnzipDest="$(mktemp --directory --tmpdir=$TmpDir "tmp_jb5_$AccountName.XXXXXXXX")" BackupPath="$FilePath" echo "Found backup path '$BackupPath'" echo "Found account '$AccountName'" echo "Creating temporary folder '$UnzipDest'" mkdir -p "$UnzipDest" || ErrorHelp "Destination directory error" ! [[ -d "$UnzipDest" ]] && ErrorHelp "Destination directory error" # Ensure we always clean-up the temporary dir on exit (success, error, or Ctrl-C). # The finished cPanel archive is written to "$DestDir", outside "$UnzipDest", so this is safe. trap 'rm -rf "$UnzipDest"' EXIT echo "Untaring '$BackupPath' into '$UnzipDest'" Untar "$BackupPath" "$UnzipDest" ! [[ -d "$UnzipDest/backup" ]] && Error "JetBackup5 backup directory '$UnzipDest/backup' not found" CPanelDir="$UnzipDest/cpmove-$AccountName" JB5Backup="$UnzipDest/backup" echo "Converting account '$AccountName'" echo "Working folder '$CPanelDir'" if ! [[ -d "$JB5Backup/config" ]]; then ErrorHelp "The backup does not contain the config directory" else MoveDir "$JB5Backup/config" "$CPanelDir/" # Extract any nested tar.gz archives in config/ (contents are flat, belong in cpmove root) for TGZ in "$CPanelDir/config/"*.tar.gz; do [ -f "$TGZ" ] || continue echo "Extracting nested config archive '$(basename "$TGZ")'" tar -xzf "$TGZ" -C "$CPanelDir/" # tar -xzf "$TGZ" -C "$UnzipDest/" Err=$? [[ $Err -gt 0 ]] && Error "Unable to extract '$TGZ'" rm "$TGZ" done echo "Copying config files to working folder" cp -rn $CPanelDir/config/* "$CPanelDir" # Remove config/ if it's now empty rmdir "$CPanelDir/config" 2>/dev/null fi if [[ -d "$JB5Backup/homedir" ]]; then if ! [[ -d "$CPanelDir/homedir" ]]; then MoveDir "$JB5Backup/homedir" "$CPanelDir" else rsync -ar "$JB5Backup/homedir" "$CPanelDir" fi # Extract any nested tar.gz archives in homedir/ (contents are flat home dir files) for TGZ in "$CPanelDir/homedir/"*.tar.gz; do [ -f "$TGZ" ] || continue echo "Extracting nested homedir archive '$(basename "$TGZ")'" tar -xzf "$TGZ" -C "$CPanelDir/homedir/" Err=$? [[ $Err -gt 0 ]] && Error "Unable to extract '$TGZ'" rm "$TGZ" done fi if [[ -d "$JB5Backup/database" ]] ; then echo "Converting databases" mkdir -p "$CPanelDir/mysql" # JB5 mixes MySQL dumps (gzipped *.sql.gz) and PostgreSQL dumps (pg_dump # custom format, misleadingly named *.tar). Detect by magic bytes rather # than by file name, since the file names are not trustworthy. for DB in "$JB5Backup/database/"*; do [ -f "$DB" ] || continue Name="${DB##*/}" if [ "$(head -c 5 "$DB")" = "PGDMP" ]; then # PostgreSQL custom-format dump -> convert to plain SQL in psql/ command -v pg_restore >/dev/null 2>&1 || Error "pg_restore not found; cannot convert PostgreSQL dump '$Name'" mkdir -p "$CPanelDir/psql" DbName="${Name%.tar}" echo "Converting PostgreSQL database '$DbName'" pg_restore -f "$CPanelDir/psql/$DbName.sql" "$DB" || Error "pg_restore failed for PostgreSQL database '$DbName'" else # MySQL dump (gzip or already-plain SQL) -> mysql/ mv "$DB" "$CPanelDir/mysql/" fi done # Decompress any gzipped MySQL dumps; leave already-plain .sql files untouched for GZ in "$CPanelDir/mysql/"*.gz; do [ -f "$GZ" ] || continue gunzip "$GZ" || Error "Unable to extract database file '$GZ'" done fi [[ -d "$JB5Backup/database_user" ]] && CreateMySQLfile "$JB5Backup/database_user" "$CPanelDir/mysql.sql" if [[ -d "$JB5Backup/email" ]]; then MoveDir "$JB5Backup/email" "$CPanelDir/homedir/mail" [[ -d "$JB5Backup/jetbackup.configs/email" ]] && CreateEmailAccount "$JB5Backup/jetbackup.configs/email" "$CPanelDir/homedir/etc" fi [[ -d "$JB5Backup/ftp" ]] && CreateFTPaccount "$JB5Backup/ftp" "$CPanelDir" if [[ -d "$JB5Backup/jetbackup.configs/domain" ]]; then CreateDomains "$JB5Backup/jetbackup.configs/domain" "$CPanelDir" CreateSSLcerts "$JB5Backup/jetbackup.configs/domain" "$CPanelDir" fi if [[ -d "$JB5Backup/domain" ]]; then CreateDNSZones "$JB5Backup/domain" "$CPanelDir" fi echo "Creating final cPanel backup archive..."; Archive "cpmove-$AccountName.tar.gz" echo "Converting Done!" echo "Temporary working folder '$UnzipDest' will be removed automatically." echo -e "Your cPanel backup:\n$DestDir/cpmove-$AccountName.tar.gz"


It works perfect
Great work, thanks!
hi, i have a question,
how we can select a backup from date?
i mean an account have many backups like daily/weekly/monthly
and how we can say which one we want to create?
The convert script works on an already downloaded backup, which means you already selected the backup you want to convert.
What license is this code released under? e.g. Public Domain or MIT License?
https://opensource.guide/legal/#which-open-source-license-is-appropriate-for-my-project
Your code was a great starting point, but I’ve made a lot of fixes that I’d like to release, as I found issues/limitations with most parts of the cPanel backup it created.
Hi Chris,
Thank you for sharing! I believe the MIT License would be the most appropriate here.
Please share a link to your revision, I am interested to see the changes!
Thanks
Sorry for the delay, I had to get approval for releasing my revised script. I’ve released it on GitHub, in the hope of encouraging other people to improve it further:
https://github.com/cshandley-uk/bash_jb5-to-cpanel-convertor
Let me know if you’d like any changes to the README.
Most notably it fixes the following issues I ran into with the generated cPanel backups:
* It failed to restore addon, alias & sub domains.
* It failed to restore mailboxes.
* It failed to restore SSL certificates (at least on the hosting I was using).
* It didn’t restore DNS zones.
There are Git commits for each of those:
https://github.com/cshandley-uk/bash_jb5-to-cpanel-convertor/commit/3e2affc63bb1dea28d8df43cddbaff4b9c75d541
https://github.com/cshandley-uk/bash_jb5-to-cpanel-convertor/commit/505db88a354f25a3ccd4f572e12ad9db9f29de16
https://github.com/cshandley-uk/bash_jb5-to-cpanel-convertor/commit/eb40cb4efd38c0805d20756286a4dd48d73c4684
https://github.com/cshandley-uk/bash_jb5-to-cpanel-convertor/commit/37de8b9e7d0950d0b9ab51721bb374b193f20334
Other significant changes I made to the script:
* It needs the “jq” command to have been installed.
* I removed the –fetch option which caused the local server to generate a new JetBackup 5 backup, as this is only useful if you have root access to the source server – in which case you could just re-enable cPanel’s built-in backup functionality anyway. The –fetch code was just extra complexity that I didn’t need when trying to understand & improve the script, and I would have been unable to test it anyway.
* I made it allocate a proper /tmp folder for storing temporary files (e.g. unpacked archive), which is always deleted – rather than leaving a randomly named folder in the destination that the user must manually delete. Currently it assumes root access when creating the /tmp folder, but this could be easily fixed.
I also made a lot of cosmetic changes to make it easier for me to understand & edit the script.
Thanks for sharing Chris! Looks really good and the commits links is very useful 🙂
can it be run on local, for downloaded jetbackup file download.XXX.XXX.tar.gz
The script itself downloads the backup then refactor it to the cPanel format, so in theory – yes, you will however need to change the script to skip the download part