Backup Won't Restore

Somehow deactivating a wordpress plugin messed up my website. I decided to delete the wordpress install and start again. I also deleted the database.
I tried to restore the backup I had using the " v-restore-user" command.
It failed and only the Wordpress files restored.


root@hsp:~# cd /backup
root@hsp:/backup# v-restore-user taco taco.2024-08-11_05-11-32.tar

-- WEB --
2024-08-14 02:24:06 innovativeworks.biz
Error: apache2 restart failed
Error: Web restart failed

So, I really only want the database and the website to restore. How do I do that? Why did the restore fail?

The HestiaCP team will immediately disagree with my statement (as they have done in the past) that backup and restore requires a huge changes in logic. To me it’s a logic designed to function on a server that does not have any use and is fresh. But after the webserver has been used thereafter things becomes messy.

The solution to your problem is very simple:

Run the same command TWICE, when it throws an error like above for the first time!

there are multiple positional parameters that can be passed to the script. doesnt look like you passed any. one would have to view the script to determine the default response

root@duserver:$HESTIA/bin# ./v-restore-user
Usage: v-restore-user USER BACKUP [WEB] [DNS] [MAIL] [DB] [CRON] [UDIR] [NOTIFY]

v-restore-user user file restores everything

Step 1: Check the logs why it is not restarting …

Thanks. I just saw if the variable wasn’t set to no. Probably missed if the variable is unset and I don’t have it In front of me right now. Sorry for the confusion

edit - so any section of the restore you want skipped you put ‘no’ as the positional parameter. This would only restorer WEB and DB

v-restore-user USER backup_file_name yes no no yes no no no

Correct.

However, let me warn you again. The error of failed restart is not dependent on what aspect of the tar file you are trying to restore.

If that error is triggered, you will have to repeat the same command again. In the first step if the error is thrown on apache restart, then it would stop. After you repeat the same command, it will restart and continue to restore DB.

But in case of this restart error, you will have to restart TWICE!

I found that this was probably to the “sandbox mode” issue with mariadb - and after fighting to fix a ton of websites, I came up with this fix.



#!/usr/bin/env bash

HestiaCP MariaDB dump sandbox-header compatibility patch.

Applies to classic .tar and Restic database restores because both use

/usr/local/hestia/func/rebuild.sh::import_mysql_database.

Does not modify saved backup archives or live database contents.

set -euo pipefail

if [[ ${EUID} -ne 0 ]]; then
echo 'ERROR: Run this installer as root (sudo -i).' >&2
exit 1
fi

TARGET='/usr/local/hestia/func/rebuild.sh'
PATCH_COMMAND='/usr/local/sbin/hestia-sandbox-import-fix'
HOOK='/etc/hestiacp/hooks/post_install.sh'

if [[ ! -f "$TARGET" ]]; then
echo "ERROR: Missing Hestia helper: $TARGET" >&2
exit 1
fi

if ! command -v mariadb >/dev/null 2>&1; then
echo 'ERROR: This patch is intended for Hestia installations with a MariaDB client.' >&2
exit 1
fi

if ! mariadb --help 2>&1 | grep -F -- '--sandbox' >/dev/null; then
echo 'ERROR: Installed MariaDB client does not advertise --sandbox.' >&2
echo 'Upgrade the MariaDB client before applying this patch.' >&2
exit 1
fi

python3 - "$TARGET" <<'PY'
import os
import pathlib
import shutil
import subprocess
import sys
import tempfile
from datetime import datetime, timezone

file = pathlib.Path(sys.argv[1])
source = file.read_text(encoding='utf-8')
anchor = 'import_mysql_database() {'
ending = '\n# Import PostgreSQL dump'
marker = '# HESTIA_SANDBOX_HEADER_COMPAT_PATCH'
old_command = 'mariadb -h $HOST -u $USER -p$PASSWORD $DB < $1 > /dev/null 2>&1'
new_command = 'mariadb --sandbox -h $HOST -u $USER -p$PASSWORD $DB < "$1" > /dev/null 2>&1'

if source.count(anchor) != 1:
raise SystemExit('ERROR: Cannot safely find a unique import_mysql_database function. No changes made.')
start = source.index(anchor)
end = source.find(ending, start)
if end < 0:
raise SystemExit('ERROR: Hestia helper layout differs from expected. No changes made.')
body = source[start:end]

if marker not in body:
addon = r'''

HESTIA_SANDBOX_HEADER_COMPAT_PATCH

Only normalize the known MariaDB sandbox comment at line 1 of the temporary

extracted dump. The original backup archive is NOT changed. MariaDB's

--sandbox option below keeps the import sandboxed despite removing the line.

local hestia_sandbox_first_line
if [[ -f /usr/bin/mariadb && -f "$1" ]]; then
IFS= read -r hestia_sandbox_first_line < "$1" || true
case "$hestia_sandbox_first_line" in
'/*!999999- enable the sandbox mode */'|'/*M!999999- enable the sandbox mode */')
sed -i '1d' -- "$1" || return 1
;;
esac
fi

HESTIA_SANDBOX_HEADER_COMPAT_PATCH_END

'''
body = body.replace(anchor, anchor + addon, 1)

if old_command in body:
body = body.replace(old_command, new_command, 1)
elif new_command not in body:
raise SystemExit('ERROR: Hestia import command has changed. No changes made.')

updated = source[:start] + body + source[end:]
if updated != source:
backup_dir = pathlib.Path('/root/hestia-sandbox-fix-backups')
backup_dir.mkdir(mode=0o700, exist_ok=True)
backup_file = backup_dir / ('rebuild.sh.' + datetime.now(timezone.utc).strftime('%Y%m%dT%H%M%SZ'))
shutil.copy2(file, backup_file)
fd, filename = tempfile.mkstemp(prefix='.rebuild-sandbox-', dir=file.parent)
tmp = pathlib.Path(filename)
try:
with os.fdopen(fd, 'w', encoding='utf-8') as handle:
handle.write(updated)
stat = file.stat()
os.chmod(tmp, stat.st_mode)
os.chown(tmp, stat.st_uid, stat.st_gid)
subprocess.run(['bash', '-n', str(tmp)], check=True)
os.replace(tmp, file)
finally:
tmp.unlink(missing_ok=True)
print(f'Patched {file}; original saved at {backup_file}')
else:
print('Hestia import helper is already patched; no changes needed.')
PY

Persist the compatibility patch across HestiaCP updates without replacing

any existing contents of the supported post-install hook.

mkdir -p /etc/hestiacp/hooks
if [[ ! -f "$HOOK" ]]; then
printf '#!/usr/bin/env bash\n' > "$HOOK"
fi

if ! grep -Fq 'hestia-sandbox-import-fix' "$HOOK"; then
cat >> "$HOOK" <<'HOOK_ADDENDUM'

Restore MariaDB sandbox header compatibility fix after HestiaCP upgrades.

if [ -x /usr/local/sbin/hestia-sandbox-import-fix ]; then
/usr/local/sbin/hestia-sandbox-import-fix >> /var/log/hestia-sandbox-import-fix.log 2>&1 
|| echo 'WARNING: Hestia sandbox compatibility patch needs review.' >&2
fi
HOOK_ADDENDUM
fi
chmod +x "$HOOK"
bash -n "$HOOK"

echo 'Done. Verify with: bash -n /usr/local/hestia/func/rebuild.sh'
echo 'No backup archive, database, or SQL dump has been restored or imported.'

Save that in /root as hestia-sandbox-import-fix.sh

I sudo into root so I don’t have to keep running sudo, so these commands are all done as root.

Run:

install -m 700 \
/root/hestia_sandbox_import_fix.sh \
/usr/local/sbin/hestia-sandbox-import-fix

Then execute:

/usr/local/sbin/hestia-sandbox-import-fix

The installer checks that your MariaDB client supports the required sandbox option before modifying HestiaCP.

3. Verify the patch

Run:

bash -n /usr/local/hestia/func/rebuild.sh

There should be no output if the modified script passes Bash syntax validation.

Then run:

grep -n 'HESTIA_SANDBOX_HEADER_COMPAT_PATCH' \
/usr/local/hestia/func/rebuild.sh

You should see the patch’s beginning and ending markers.

No MariaDB or HestiaCP restart is required.

4. Protection against HestiaCP updates

The installer also creates or updates:

/etc/hestiacp/hooks/post_install.sh

HestiaCP officially supports post-install hooks for reapplying customizations after updates.

The hook will rerun the patch installer after an update. If HestiaCP changes its import code substantially, the patcher will stop rather than modify an unrecognized function.

So anyone dealing with the dreaded

/*!999999- enable the sandbox mode */

This will fix that. I had to reinstall 90 sites on a server and almost lost my mind when none of the databases installed. I know the HestiaCP team has replied to other posts that it is not their fault, it is mariadb - but this is a simple fix for everyone, and actually should be included in core.

Enjoy!

Chris

Check the pasted code because it doesn’t include hashes for the comments.