<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:dc="http://purl.org/dc/elements/1.1/">
	<channel>
		<title><![CDATA[AdminsForum - aaPanel Backups & Migration Guides]]></title>
		<link>https://adminsforum.com/</link>
		<description><![CDATA[AdminsForum - https://adminsforum.com]]></description>
		<pubDate>Thu, 15 Oct 2026 07:04:57 +0000</pubDate>
		<generator>MyBB</generator>
		<item>
			<title><![CDATA[Back Up and Restore a Flask App on an aaPanel Server]]></title>
			<link>https://adminsforum.com/Thread-guide-back-up-and-restore-a-flask-app-on-an-aapanel-server</link>
			<pubDate>Wed, 14 Oct 2026 15:11:58 +0800</pubDate>
			<dc:creator><![CDATA[<a href="https://adminsforum.com/member.php?action=profile&uid=2">DEV</a>]]></dc:creator>
			<guid isPermaLink="false">https://adminsforum.com/Thread-guide-back-up-and-restore-a-flask-app-on-an-aapanel-server</guid>
			<description><![CDATA[<span style="font-weight: bold;" class="mycode_b">A backup is useful only when you can rebuild and run the application from it. This SSH-based guide backs up a small Flask project hosted by aaPanel, restores it outside the live website folder and tests it on a separate localhost port.</span><br />
<br />
<span style="font-weight: bold;" class="mycode_b">Tested lab:</span> Ubuntu 22.04.5, aaPanel Free 8.0.7 and a Flask/Gunicorn sample. This is a source-and-dependency recovery exercise, not a complete VPS image or a walkthrough of an aaPanel backup plugin.<br />
<br />
<!-- start: postbit_attachments_attachment -->
<br /><!-- start: attachment_icon -->
<img src="https://adminsforum.com/images/attachtypes/image.png" title="JPG Image" border="0" alt=".jpg" />
<!-- end: attachment_icon -->&nbsp;&nbsp;<a href="attachment.php?aid=221" target="_blank" title="">python-backup-workflow-20261014.jpg</a> (Size: 107.98 KB / Downloads: 5)
<!-- end: postbit_attachments_attachment --><br />
<span style="font-style: italic;" class="mycode_i">Restore workflow diagram. The live app and the recovery test remain separate.</span><br />
<br />
<span style="font-weight: bold;" class="mycode_b">1. Define what must be recovered</span><br />
Our sample has app.py and requirements.txt and no database, uploads or secret configuration. A real app may also need a consistent database export, uploaded files, environment secrets, Nginx configuration and its startup settings. Inventory those separately before claiming a complete backup.<br />
<br />
The live project directory is /www/wwwroot/af-flask-lab. Its Gunicorn command uses app:app and binds 127.0.0.1:3200. Record your environment path, Python version, startup user, domain and mapping port in a protected recovery note.<br />
<br />
<span style="font-weight: bold;" class="mycode_b">2. Record the application's packages</span><br />
Place a reviewed requirements.txt beside app.py. Our small sample contains:<br />
<div class="codeblock"><div class="title af-code-title"><span>Code:</span><button type="button" class="af-code-copy" aria-label="Copy code" title="Copy code"><i class="far fa-copy" aria-hidden="true"></i><span>Copy</span></button><span class="af-code-status" role="status" aria-live="polite"></span></div><div class="body" dir="ltr"><code>Flask==3.1.3
gunicorn==26.2.0</code></div></div>These are the versions tested in this lab. This pins direct dependencies; it does not lock every transitive dependency. For stronger repeatability, retain a reviewed full dependency snapshot or a suitable lock file and test it in a clean environment.<br />
<br />
<span style="font-weight: bold;" class="mycode_b">3. Create a protected source archive</span><br />
Choose a new archive name so you do not overwrite an older recovery point. From the VPS terminal, the equivalent command for our two-file sample is:<br />
<div class="codeblock"><div class="title af-code-title"><span>Code:</span><button type="button" class="af-code-copy" aria-label="Copy code" title="Copy code"><i class="far fa-copy" aria-hidden="true"></i><span>Copy</span></button><span class="af-code-status" role="status" aria-live="polite"></span></div><div class="body" dir="ltr"><code>tar -czf /www/backup/af-flask-20261014.tar.gz   -C /www/wwwroot af-flask-lab/app.py af-flask-lab/requirements.txt
chmod 600 /www/backup/af-flask-20261014.tar.gz
tar -tzf /www/backup/af-flask-20261014.tar.gz</code></div></div>Check that both expected files are listed. Our archive was 377 bytes because this is a tiny text-only sample, not a full production application.<br />
<br />
Do not publish backup archives inside a website document root. Rebuild the virtual environment rather than assuming a copied environment is portable between server paths or operating systems. Save a protected off-site copy through your approved backup destination; a local archive alone does not protect against losing the VPS. Off-site transfer was not performed in this exercise.<br />
<br />
<span style="font-weight: bold;" class="mycode_b">4. Restore into a new isolated directory</span><br />
Use a new directory that does not already contain files:<br />
<div class="codeblock"><div class="title af-code-title"><span>Code:</span><button type="button" class="af-code-copy" aria-label="Copy code" title="Copy code"><i class="far fa-copy" aria-hidden="true"></i><span>Copy</span></button><span class="af-code-status" role="status" aria-live="polite"></span></div><div class="body" dir="ltr"><code>mkdir /www/af-flask-restore-20261014
tar -xzf /www/backup/af-flask-20261014.tar.gz   -C /www/af-flask-restore-20261014</code></div></div>Only extract your trusted archive after inspecting its file list. Do not extract into the live project for a rehearsal. The restored app is now under /www/af-flask-restore-20261014/af-flask-lab.<br />
<br />
Compare app.py and requirements.txt with the source copies. For example:<br />
<div class="codeblock"><div class="title af-code-title"><span>Code:</span><button type="button" class="af-code-copy" aria-label="Copy code" title="Copy code"><i class="far fa-copy" aria-hidden="true"></i><span>Copy</span></button><span class="af-code-status" role="status" aria-live="polite"></span></div><div class="body" dir="ltr"><code>sha256sum /www/wwwroot/af-flask-lab/app.py
sha256sum /www/af-flask-restore-20261014/af-flask-lab/app.py</code></div></div>Our test compared both files with SHA-256 and both matched. A matching hash proves the file content matches; it does not yet prove the app can run.<br />
<br />
<span style="font-weight: bold;" class="mycode_b">5. Build a fresh environment</span><br />
Use a Python version compatible with the application. Our existing lab uses /usr/bin/python3.10; choose a maintained compatible release for a new deployment. Ubuntu's matching venv package must already be installed.<br />
<div class="codeblock"><div class="title af-code-title"><span>Code:</span><button type="button" class="af-code-copy" aria-label="Copy code" title="Copy code"><i class="far fa-copy" aria-hidden="true"></i><span>Copy</span></button><span class="af-code-status" role="status" aria-live="polite"></span></div><div class="body" dir="ltr"><code>python3 -m venv /www/af-flask-restore-20261014/venv
/www/af-flask-restore-20261014/venv/bin/python -m pip install   -r /www/af-flask-restore-20261014/af-flask-lab/requirements.txt
/www/af-flask-restore-20261014/venv/bin/python -m pip check</code></div></div>Our fresh environment installed the recorded direct versions and pip check reported <span style="font-weight: bold;" class="mycode_b">No broken requirements found</span>. Install from trusted package sources. If your project needs OS libraries, document and rebuild those too.<br />
<br />
<span style="font-weight: bold;" class="mycode_b">6. Run the restored app on a different local port</span><br />
Set permissions only on the isolated restore directory for the intended application user. In our lab that user is www. From an administrator terminal:<br />
<div class="codeblock"><div class="title af-code-title"><span>Code:</span><button type="button" class="af-code-copy" aria-label="Copy code" title="Copy code"><i class="far fa-copy" aria-hidden="true"></i><span>Copy</span></button><span class="af-code-status" role="status" aria-live="polite"></span></div><div class="body" dir="ltr"><code>chown -R www:www /www/af-flask-restore-20261014
cd /www/af-flask-restore-20261014/af-flask-lab
runuser -u www -- /www/af-flask-restore-20261014/venv/bin/gunicorn   --workers 1 --bind 127.0.0.1:3202 app:app</code></div></div>This foreground command occupies that terminal. From a second terminal:<br />
<div class="codeblock"><div class="title af-code-title"><span>Code:</span><button type="button" class="af-code-copy" aria-label="Copy code" title="Copy code"><i class="far fa-copy" aria-hidden="true"></i><span>Copy</span></button><span class="af-code-status" role="status" aria-live="polite"></span></div><div class="body" dir="ltr"><code>curl -i http://127.0.0.1:3202/</code></div></div>Our restore returned HTTP 200 and AdminsForum Flask lab. Port 3202 stayed local and did not replace the live app on 3200. Stop the foreground recovery process with Ctrl+C when the test is finished. We stopped the temporary test process and rechecked the live HTTPS site, which still returned HTTP 200.<br />
<br />
<span style="font-weight: bold;" class="mycode_b">Before using this for a real recovery</span><br />
Test database connectivity, uploads, background jobs, secrets, logging and the expected user workflow. A two-file Flask test cannot establish those properties. Restore missing resources before changing the live domain or project path. Plan cutover and rollback separately; a rehearsal should not overwrite your running deployment.<br />
<br />
<span style="font-weight: bold;" class="mycode_b">Completion checklist</span><ul class="mycode_list"><li>Backup contents inspected and protected.<br />
</li>
<li>Isolated restore directory used.<br />
</li>
<li>Source file hashes compared.<br />
</li>
<li>Fresh environment built and dependencies checked.<br />
</li>
<li>Restored application tested on a separate local port.<br />
</li>
<li>Temporary process stopped and live website checked.<br />
</li>
<li>Off-site retention and application-specific data still included in the wider recovery plan.<br />
</li>
</ul>
<br />
<span style="font-style: italic;" class="mycode_i">AdminsForum lab-tested guide. Illustration is a workflow diagram; commands describe the tested SSH recovery method.</span>]]></description>
			<content:encoded><![CDATA[<span style="font-weight: bold;" class="mycode_b">A backup is useful only when you can rebuild and run the application from it. This SSH-based guide backs up a small Flask project hosted by aaPanel, restores it outside the live website folder and tests it on a separate localhost port.</span><br />
<br />
<span style="font-weight: bold;" class="mycode_b">Tested lab:</span> Ubuntu 22.04.5, aaPanel Free 8.0.7 and a Flask/Gunicorn sample. This is a source-and-dependency recovery exercise, not a complete VPS image or a walkthrough of an aaPanel backup plugin.<br />
<br />
<!-- start: postbit_attachments_attachment -->
<br /><!-- start: attachment_icon -->
<img src="https://adminsforum.com/images/attachtypes/image.png" title="JPG Image" border="0" alt=".jpg" />
<!-- end: attachment_icon -->&nbsp;&nbsp;<a href="attachment.php?aid=221" target="_blank" title="">python-backup-workflow-20261014.jpg</a> (Size: 107.98 KB / Downloads: 5)
<!-- end: postbit_attachments_attachment --><br />
<span style="font-style: italic;" class="mycode_i">Restore workflow diagram. The live app and the recovery test remain separate.</span><br />
<br />
<span style="font-weight: bold;" class="mycode_b">1. Define what must be recovered</span><br />
Our sample has app.py and requirements.txt and no database, uploads or secret configuration. A real app may also need a consistent database export, uploaded files, environment secrets, Nginx configuration and its startup settings. Inventory those separately before claiming a complete backup.<br />
<br />
The live project directory is /www/wwwroot/af-flask-lab. Its Gunicorn command uses app:app and binds 127.0.0.1:3200. Record your environment path, Python version, startup user, domain and mapping port in a protected recovery note.<br />
<br />
<span style="font-weight: bold;" class="mycode_b">2. Record the application's packages</span><br />
Place a reviewed requirements.txt beside app.py. Our small sample contains:<br />
<div class="codeblock"><div class="title af-code-title"><span>Code:</span><button type="button" class="af-code-copy" aria-label="Copy code" title="Copy code"><i class="far fa-copy" aria-hidden="true"></i><span>Copy</span></button><span class="af-code-status" role="status" aria-live="polite"></span></div><div class="body" dir="ltr"><code>Flask==3.1.3
gunicorn==26.2.0</code></div></div>These are the versions tested in this lab. This pins direct dependencies; it does not lock every transitive dependency. For stronger repeatability, retain a reviewed full dependency snapshot or a suitable lock file and test it in a clean environment.<br />
<br />
<span style="font-weight: bold;" class="mycode_b">3. Create a protected source archive</span><br />
Choose a new archive name so you do not overwrite an older recovery point. From the VPS terminal, the equivalent command for our two-file sample is:<br />
<div class="codeblock"><div class="title af-code-title"><span>Code:</span><button type="button" class="af-code-copy" aria-label="Copy code" title="Copy code"><i class="far fa-copy" aria-hidden="true"></i><span>Copy</span></button><span class="af-code-status" role="status" aria-live="polite"></span></div><div class="body" dir="ltr"><code>tar -czf /www/backup/af-flask-20261014.tar.gz   -C /www/wwwroot af-flask-lab/app.py af-flask-lab/requirements.txt
chmod 600 /www/backup/af-flask-20261014.tar.gz
tar -tzf /www/backup/af-flask-20261014.tar.gz</code></div></div>Check that both expected files are listed. Our archive was 377 bytes because this is a tiny text-only sample, not a full production application.<br />
<br />
Do not publish backup archives inside a website document root. Rebuild the virtual environment rather than assuming a copied environment is portable between server paths or operating systems. Save a protected off-site copy through your approved backup destination; a local archive alone does not protect against losing the VPS. Off-site transfer was not performed in this exercise.<br />
<br />
<span style="font-weight: bold;" class="mycode_b">4. Restore into a new isolated directory</span><br />
Use a new directory that does not already contain files:<br />
<div class="codeblock"><div class="title af-code-title"><span>Code:</span><button type="button" class="af-code-copy" aria-label="Copy code" title="Copy code"><i class="far fa-copy" aria-hidden="true"></i><span>Copy</span></button><span class="af-code-status" role="status" aria-live="polite"></span></div><div class="body" dir="ltr"><code>mkdir /www/af-flask-restore-20261014
tar -xzf /www/backup/af-flask-20261014.tar.gz   -C /www/af-flask-restore-20261014</code></div></div>Only extract your trusted archive after inspecting its file list. Do not extract into the live project for a rehearsal. The restored app is now under /www/af-flask-restore-20261014/af-flask-lab.<br />
<br />
Compare app.py and requirements.txt with the source copies. For example:<br />
<div class="codeblock"><div class="title af-code-title"><span>Code:</span><button type="button" class="af-code-copy" aria-label="Copy code" title="Copy code"><i class="far fa-copy" aria-hidden="true"></i><span>Copy</span></button><span class="af-code-status" role="status" aria-live="polite"></span></div><div class="body" dir="ltr"><code>sha256sum /www/wwwroot/af-flask-lab/app.py
sha256sum /www/af-flask-restore-20261014/af-flask-lab/app.py</code></div></div>Our test compared both files with SHA-256 and both matched. A matching hash proves the file content matches; it does not yet prove the app can run.<br />
<br />
<span style="font-weight: bold;" class="mycode_b">5. Build a fresh environment</span><br />
Use a Python version compatible with the application. Our existing lab uses /usr/bin/python3.10; choose a maintained compatible release for a new deployment. Ubuntu's matching venv package must already be installed.<br />
<div class="codeblock"><div class="title af-code-title"><span>Code:</span><button type="button" class="af-code-copy" aria-label="Copy code" title="Copy code"><i class="far fa-copy" aria-hidden="true"></i><span>Copy</span></button><span class="af-code-status" role="status" aria-live="polite"></span></div><div class="body" dir="ltr"><code>python3 -m venv /www/af-flask-restore-20261014/venv
/www/af-flask-restore-20261014/venv/bin/python -m pip install   -r /www/af-flask-restore-20261014/af-flask-lab/requirements.txt
/www/af-flask-restore-20261014/venv/bin/python -m pip check</code></div></div>Our fresh environment installed the recorded direct versions and pip check reported <span style="font-weight: bold;" class="mycode_b">No broken requirements found</span>. Install from trusted package sources. If your project needs OS libraries, document and rebuild those too.<br />
<br />
<span style="font-weight: bold;" class="mycode_b">6. Run the restored app on a different local port</span><br />
Set permissions only on the isolated restore directory for the intended application user. In our lab that user is www. From an administrator terminal:<br />
<div class="codeblock"><div class="title af-code-title"><span>Code:</span><button type="button" class="af-code-copy" aria-label="Copy code" title="Copy code"><i class="far fa-copy" aria-hidden="true"></i><span>Copy</span></button><span class="af-code-status" role="status" aria-live="polite"></span></div><div class="body" dir="ltr"><code>chown -R www:www /www/af-flask-restore-20261014
cd /www/af-flask-restore-20261014/af-flask-lab
runuser -u www -- /www/af-flask-restore-20261014/venv/bin/gunicorn   --workers 1 --bind 127.0.0.1:3202 app:app</code></div></div>This foreground command occupies that terminal. From a second terminal:<br />
<div class="codeblock"><div class="title af-code-title"><span>Code:</span><button type="button" class="af-code-copy" aria-label="Copy code" title="Copy code"><i class="far fa-copy" aria-hidden="true"></i><span>Copy</span></button><span class="af-code-status" role="status" aria-live="polite"></span></div><div class="body" dir="ltr"><code>curl -i http://127.0.0.1:3202/</code></div></div>Our restore returned HTTP 200 and AdminsForum Flask lab. Port 3202 stayed local and did not replace the live app on 3200. Stop the foreground recovery process with Ctrl+C when the test is finished. We stopped the temporary test process and rechecked the live HTTPS site, which still returned HTTP 200.<br />
<br />
<span style="font-weight: bold;" class="mycode_b">Before using this for a real recovery</span><br />
Test database connectivity, uploads, background jobs, secrets, logging and the expected user workflow. A two-file Flask test cannot establish those properties. Restore missing resources before changing the live domain or project path. Plan cutover and rollback separately; a rehearsal should not overwrite your running deployment.<br />
<br />
<span style="font-weight: bold;" class="mycode_b">Completion checklist</span><ul class="mycode_list"><li>Backup contents inspected and protected.<br />
</li>
<li>Isolated restore directory used.<br />
</li>
<li>Source file hashes compared.<br />
</li>
<li>Fresh environment built and dependencies checked.<br />
</li>
<li>Restored application tested on a separate local port.<br />
</li>
<li>Temporary process stopped and live website checked.<br />
</li>
<li>Off-site retention and application-specific data still included in the wider recovery plan.<br />
</li>
</ul>
<br />
<span style="font-style: italic;" class="mycode_i">AdminsForum lab-tested guide. Illustration is a workflow diagram; commands describe the tested SSH recovery method.</span>]]></content:encoded>
		</item>
		<item>
			<title><![CDATA[Back Up and Restore a Node.js App on an aaPanel Server]]></title>
			<link>https://adminsforum.com/Thread-guide-back-up-and-restore-a-node-js-app-on-an-aapanel-server</link>
			<pubDate>Wed, 14 Oct 2026 11:00:27 +0800</pubDate>
			<dc:creator><![CDATA[<a href="https://adminsforum.com/member.php?action=profile&uid=2">DEV</a>]]></dc:creator>
			<guid isPermaLink="false">https://adminsforum.com/Thread-guide-back-up-and-restore-a-node-js-app-on-an-aapanel-server</guid>
			<description><![CDATA[<span style="font-weight: bold;" class="mycode_b">A backup is useful only if you can restore and run the application. This guide backs up our aaPanel-managed Node.js sample, extracts it into a separate folder, compares the restored files and runs the copy on a temporary localhost port. The live website is not replaced.</span><br />
<br />
<!-- start: postbit_attachments_attachment -->
<br /><!-- start: attachment_icon -->
<img src="https://adminsforum.com/images/attachtypes/image.png" title="PNG Image" border="0" alt=".png" />
<!-- end: attachment_icon -->&nbsp;&nbsp;<a href="attachment.php?aid=207" target="_blank" title="">node-backup-workflow-20261014.png</a> (Size: 64.64 KB / Downloads: 4)
<!-- end: postbit_attachments_attachment --><br />
<span style="font-style: italic;" class="mycode_i">Backup and isolated restore workflow, based on the lab test below.</span><br />
<br />
<span style="font-weight: bold;" class="mycode_b">Tested setup:</span> Ubuntu 22.04.5 LTS, aaPanel Free 8.0.7, Node.js 24.21.0. Source folder /www/wwwroot/af-node-lab; project afnodelab; live domain node.adminslab.com. Tested on 14 October 2026. These steps use SSH on the aaPanel server; they do not demonstrate aaPanel's native Backup / Restore button.<br />
<br />
<span style="font-weight: bold;" class="mycode_b">1. Decide what the backup must include</span><br />
For this dependency-free sample, we preserved server.js, package.json and yarn.lock. For a real application, also identify configuration, required environment variables, uploaded files, generated assets and external services.<br />
<br />
A source-file archive is not a database backup or a full aaPanel configuration backup. Record the project name, runtime, run user, startup command, port, domain mapping and Boot setting separately. Store secrets securely. Do not put an archive containing credentials under a publicly served website directory.<br />
<br />
<span style="font-weight: bold;" class="mycode_b">2. Check the live app before starting</span><br />
<div class="codeblock"><div class="title af-code-title"><span>Code:</span><button type="button" class="af-code-copy" aria-label="Copy code" title="Copy code"><i class="far fa-copy" aria-hidden="true"></i><span>Copy</span></button><span class="af-code-status" role="status" aria-live="polite"></span></div><div class="body" dir="ltr"><code>curl -I https://node.adminslab.com/
ls -l /www/wwwroot/af-node-lab
df -h /www</code></div></div>Use your own domain and directory. Confirm the app is healthy and enough disk space is available. Our live app returned 200 before the test. For an application writing files or a database, plan a consistent backup process; copying changing files does not automatically produce a consistent recovery point.<br />
<br />
<span style="font-weight: bold;" class="mycode_b">3. Create the archive outside the website root</span><br />
The following commands are for our lab. Use a unique archive filename to avoid overwriting an older backup:<br />
<div class="codeblock"><div class="title af-code-title"><span>Code:</span><button type="button" class="af-code-copy" aria-label="Copy code" title="Copy code"><i class="far fa-copy" aria-hidden="true"></i><span>Copy</span></button><span class="af-code-status" role="status" aria-live="polite"></span></div><div class="body" dir="ltr"><code>sudo tar --exclude=af-node-lab/node_modules   -czf /www/backup/af-node-20261014.tar.gz   -C /www/wwwroot af-node-lab
sudo chmod 600 /www/backup/af-node-20261014.tar.gz</code></div></div>The -C option changes the base directory before archiving. The archive contains the af-node-lab folder rather than absolute server paths. We excluded node_modules for this sample; a real app needs a reproducible dependency installation or another deliberate dependency-backup strategy. Preserve its lockfile and build requirements.<br />
<br />
Our archive was 878 bytes because the sample contains only a few tiny source and lock files. That size is not representative of a real application.<br />
<br />
<span style="font-weight: bold;" class="mycode_b">4. Inspect the archive and keep an off-server copy</span><br />
<div class="codeblock"><div class="title af-code-title"><span>Code:</span><button type="button" class="af-code-copy" aria-label="Copy code" title="Copy code"><i class="far fa-copy" aria-hidden="true"></i><span>Copy</span></button><span class="af-code-status" role="status" aria-live="polite"></span></div><div class="body" dir="ltr"><code>sudo tar -tzf /www/backup/af-node-20261014.tar.gz
sudo sha256sum /www/backup/af-node-20261014.tar.gz</code></div></div>Check that the expected files appear. A readable archive list is useful, but it does not prove the app can run after restoration. Transfer a protected copy to a separate backup location and record its checksum. Our lab test verified a local archive and restore; an off-server transfer was not part of this test.<br />
<br />
<span style="font-weight: bold;" class="mycode_b">5. Restore into a new directory</span><br />
Choose a directory that does not already exist. Never extract over the live app as your first recovery test:<br />
<div class="codeblock"><div class="title af-code-title"><span>Code:</span><button type="button" class="af-code-copy" aria-label="Copy code" title="Copy code"><i class="far fa-copy" aria-hidden="true"></i><span>Copy</span></button><span class="af-code-status" role="status" aria-live="polite"></span></div><div class="body" dir="ltr"><code>sudo mkdir /www/af-node-restore-20261014
sudo tar -xzf /www/backup/af-node-20261014.tar.gz   -C /www/af-node-restore-20261014</code></div></div>The restored app is now under /www/af-node-restore-20261014/af-node-lab. This directory is separate from the live application's document root.<br />
<br />
Before modifying the copy, compare hashes:<br />
<div class="codeblock"><div class="title af-code-title"><span>Code:</span><button type="button" class="af-code-copy" aria-label="Copy code" title="Copy code"><i class="far fa-copy" aria-hidden="true"></i><span>Copy</span></button><span class="af-code-status" role="status" aria-live="polite"></span></div><div class="body" dir="ltr"><code>sha256sum /www/wwwroot/af-node-lab/server.js
sha256sum /www/af-node-restore-20261014/af-node-lab/server.js</code></div></div>Repeat for package.json and yarn.lock. Matching digests confirm identical file contents at this point. Our test compared all three and they matched. A file checksum does not validate database contents or application behaviour.<br />
<br />
<span style="font-weight: bold;" class="mycode_b">6. Prepare the restored copy for an isolated test</span><br />
Set ownership only on the separate test directory:<br />
<div class="codeblock"><div class="title af-code-title"><span>Code:</span><button type="button" class="af-code-copy" aria-label="Copy code" title="Copy code"><i class="far fa-copy" aria-hidden="true"></i><span>Copy</span></button><span class="af-code-status" role="status" aria-live="polite"></span></div><div class="body" dir="ltr"><code>sudo chown -R www:www /www/af-node-restore-20261014</code></div></div>In the restored server.js only, change the sample port from 3100 to 3102 and update its startup message to match. Leave the live server.js untouched. Confirm that the temporary port is unused:<br />
<div class="codeblock"><div class="title af-code-title"><span>Code:</span><button type="button" class="af-code-copy" aria-label="Copy code" title="Copy code"><i class="far fa-copy" aria-hidden="true"></i><span>Copy</span></button><span class="af-code-status" role="status" aria-live="polite"></span></div><div class="body" dir="ltr"><code>ss -ltn | grep ':3102'</code></div></div>No matching listener should be present before this test. Do not use an occupied port. Keep the sample bound to 127.0.0.1 so the temporary copy is not exposed publicly.<br />
<br />
Check its JavaScript syntax:<br />
<div class="codeblock"><div class="title af-code-title"><span>Code:</span><button type="button" class="af-code-copy" aria-label="Copy code" title="Copy code"><i class="far fa-copy" aria-hidden="true"></i><span>Copy</span></button><span class="af-code-status" role="status" aria-live="polite"></span></div><div class="body" dir="ltr"><code>/www/server/nodejs/v24.21.0/bin/node --check   /www/af-node-restore-20261014/af-node-lab/server.js</code></div></div>Replace the runtime path with your installed version. Real applications may also need dependencies, compilation and test environment configuration. Do not connect a recovery test to production services that could send mail, charge payments or modify live data.<br />
<br />
<span style="font-weight: bold;" class="mycode_b">7. Run the copy and check its response</span><br />
In one SSH session, start it in the foreground as www:<br />
<div class="codeblock"><div class="title af-code-title"><span>Code:</span><button type="button" class="af-code-copy" aria-label="Copy code" title="Copy code"><i class="far fa-copy" aria-hidden="true"></i><span>Copy</span></button><span class="af-code-status" role="status" aria-live="polite"></span></div><div class="body" dir="ltr"><code>sudo runuser -u www -- /www/server/nodejs/v24.21.0/bin/node   /www/af-node-restore-20261014/af-node-lab/server.js</code></div></div>In a second SSH session:<br />
<div class="codeblock"><div class="title af-code-title"><span>Code:</span><button type="button" class="af-code-copy" aria-label="Copy code" title="Copy code"><i class="far fa-copy" aria-hidden="true"></i><span>Copy</span></button><span class="af-code-status" role="status" aria-live="polite"></span></div><div class="body" dir="ltr"><code>curl -i http://127.0.0.1:3102/
curl -I https://node.adminslab.com/</code></div></div>The restored sample should return HTTP 200 and the AdminsForum Node.js Lab page. The live domain should still return 200 independently. We verified the restored response and the live domain during our test.<br />
<br />
When finished, stop the foreground test with Ctrl+C. Our test also stopped its temporary process after validation; the live app remained running. Confirm that the temporary listener has gone before reusing the port.<br />
<br />
<span style="font-weight: bold;" class="mycode_b">8. Record the recovery result</span><br />
Our test result was:<br />
<div class="codeblock"><div class="title af-code-title"><span>Code:</span><button type="button" class="af-code-copy" aria-label="Copy code" title="Copy code"><i class="far fa-copy" aria-hidden="true"></i><span>Copy</span></button><span class="af-code-status" role="status" aria-live="polite"></span></div><div class="body" dir="ltr"><code>server.js file hash: MATCH
package.json file hash: MATCH
yarn.lock file hash: MATCH
Restored app on localhost:3102: EXPECTED PAGE
Live HTTPS website: 200</code></div></div>The archive and isolated restored folder were retained for later inspection. This proves recovery of this small source-based sample, not a full server or database restore.<br />
<br />
<span style="font-weight: bold;" class="mycode_b">9. Before replacing a real deployment</span><br />
Keep the current release and its backup, restore any database consistently, verify dependencies and secrets, then plan the switch and rollback. Use aaPanel to configure the intended project directory and runtime only after the recovery copy passes its checks. Repeat response tests after the change. This guide deliberately stops before a live cutover.<br />
<br />
<span style="font-weight: bold;" class="mycode_b">Related guide:</span> <a href="https://adminsforum.com/Thread-guide-deploy-a-node-js-app-in-aapanel-with-a-domain-and-https" target="_blank" rel="noopener" class="mycode_url">Deploy a Node.js app in aaPanel with a domain and HTTPS</a>.]]></description>
			<content:encoded><![CDATA[<span style="font-weight: bold;" class="mycode_b">A backup is useful only if you can restore and run the application. This guide backs up our aaPanel-managed Node.js sample, extracts it into a separate folder, compares the restored files and runs the copy on a temporary localhost port. The live website is not replaced.</span><br />
<br />
<!-- start: postbit_attachments_attachment -->
<br /><!-- start: attachment_icon -->
<img src="https://adminsforum.com/images/attachtypes/image.png" title="PNG Image" border="0" alt=".png" />
<!-- end: attachment_icon -->&nbsp;&nbsp;<a href="attachment.php?aid=207" target="_blank" title="">node-backup-workflow-20261014.png</a> (Size: 64.64 KB / Downloads: 4)
<!-- end: postbit_attachments_attachment --><br />
<span style="font-style: italic;" class="mycode_i">Backup and isolated restore workflow, based on the lab test below.</span><br />
<br />
<span style="font-weight: bold;" class="mycode_b">Tested setup:</span> Ubuntu 22.04.5 LTS, aaPanel Free 8.0.7, Node.js 24.21.0. Source folder /www/wwwroot/af-node-lab; project afnodelab; live domain node.adminslab.com. Tested on 14 October 2026. These steps use SSH on the aaPanel server; they do not demonstrate aaPanel's native Backup / Restore button.<br />
<br />
<span style="font-weight: bold;" class="mycode_b">1. Decide what the backup must include</span><br />
For this dependency-free sample, we preserved server.js, package.json and yarn.lock. For a real application, also identify configuration, required environment variables, uploaded files, generated assets and external services.<br />
<br />
A source-file archive is not a database backup or a full aaPanel configuration backup. Record the project name, runtime, run user, startup command, port, domain mapping and Boot setting separately. Store secrets securely. Do not put an archive containing credentials under a publicly served website directory.<br />
<br />
<span style="font-weight: bold;" class="mycode_b">2. Check the live app before starting</span><br />
<div class="codeblock"><div class="title af-code-title"><span>Code:</span><button type="button" class="af-code-copy" aria-label="Copy code" title="Copy code"><i class="far fa-copy" aria-hidden="true"></i><span>Copy</span></button><span class="af-code-status" role="status" aria-live="polite"></span></div><div class="body" dir="ltr"><code>curl -I https://node.adminslab.com/
ls -l /www/wwwroot/af-node-lab
df -h /www</code></div></div>Use your own domain and directory. Confirm the app is healthy and enough disk space is available. Our live app returned 200 before the test. For an application writing files or a database, plan a consistent backup process; copying changing files does not automatically produce a consistent recovery point.<br />
<br />
<span style="font-weight: bold;" class="mycode_b">3. Create the archive outside the website root</span><br />
The following commands are for our lab. Use a unique archive filename to avoid overwriting an older backup:<br />
<div class="codeblock"><div class="title af-code-title"><span>Code:</span><button type="button" class="af-code-copy" aria-label="Copy code" title="Copy code"><i class="far fa-copy" aria-hidden="true"></i><span>Copy</span></button><span class="af-code-status" role="status" aria-live="polite"></span></div><div class="body" dir="ltr"><code>sudo tar --exclude=af-node-lab/node_modules   -czf /www/backup/af-node-20261014.tar.gz   -C /www/wwwroot af-node-lab
sudo chmod 600 /www/backup/af-node-20261014.tar.gz</code></div></div>The -C option changes the base directory before archiving. The archive contains the af-node-lab folder rather than absolute server paths. We excluded node_modules for this sample; a real app needs a reproducible dependency installation or another deliberate dependency-backup strategy. Preserve its lockfile and build requirements.<br />
<br />
Our archive was 878 bytes because the sample contains only a few tiny source and lock files. That size is not representative of a real application.<br />
<br />
<span style="font-weight: bold;" class="mycode_b">4. Inspect the archive and keep an off-server copy</span><br />
<div class="codeblock"><div class="title af-code-title"><span>Code:</span><button type="button" class="af-code-copy" aria-label="Copy code" title="Copy code"><i class="far fa-copy" aria-hidden="true"></i><span>Copy</span></button><span class="af-code-status" role="status" aria-live="polite"></span></div><div class="body" dir="ltr"><code>sudo tar -tzf /www/backup/af-node-20261014.tar.gz
sudo sha256sum /www/backup/af-node-20261014.tar.gz</code></div></div>Check that the expected files appear. A readable archive list is useful, but it does not prove the app can run after restoration. Transfer a protected copy to a separate backup location and record its checksum. Our lab test verified a local archive and restore; an off-server transfer was not part of this test.<br />
<br />
<span style="font-weight: bold;" class="mycode_b">5. Restore into a new directory</span><br />
Choose a directory that does not already exist. Never extract over the live app as your first recovery test:<br />
<div class="codeblock"><div class="title af-code-title"><span>Code:</span><button type="button" class="af-code-copy" aria-label="Copy code" title="Copy code"><i class="far fa-copy" aria-hidden="true"></i><span>Copy</span></button><span class="af-code-status" role="status" aria-live="polite"></span></div><div class="body" dir="ltr"><code>sudo mkdir /www/af-node-restore-20261014
sudo tar -xzf /www/backup/af-node-20261014.tar.gz   -C /www/af-node-restore-20261014</code></div></div>The restored app is now under /www/af-node-restore-20261014/af-node-lab. This directory is separate from the live application's document root.<br />
<br />
Before modifying the copy, compare hashes:<br />
<div class="codeblock"><div class="title af-code-title"><span>Code:</span><button type="button" class="af-code-copy" aria-label="Copy code" title="Copy code"><i class="far fa-copy" aria-hidden="true"></i><span>Copy</span></button><span class="af-code-status" role="status" aria-live="polite"></span></div><div class="body" dir="ltr"><code>sha256sum /www/wwwroot/af-node-lab/server.js
sha256sum /www/af-node-restore-20261014/af-node-lab/server.js</code></div></div>Repeat for package.json and yarn.lock. Matching digests confirm identical file contents at this point. Our test compared all three and they matched. A file checksum does not validate database contents or application behaviour.<br />
<br />
<span style="font-weight: bold;" class="mycode_b">6. Prepare the restored copy for an isolated test</span><br />
Set ownership only on the separate test directory:<br />
<div class="codeblock"><div class="title af-code-title"><span>Code:</span><button type="button" class="af-code-copy" aria-label="Copy code" title="Copy code"><i class="far fa-copy" aria-hidden="true"></i><span>Copy</span></button><span class="af-code-status" role="status" aria-live="polite"></span></div><div class="body" dir="ltr"><code>sudo chown -R www:www /www/af-node-restore-20261014</code></div></div>In the restored server.js only, change the sample port from 3100 to 3102 and update its startup message to match. Leave the live server.js untouched. Confirm that the temporary port is unused:<br />
<div class="codeblock"><div class="title af-code-title"><span>Code:</span><button type="button" class="af-code-copy" aria-label="Copy code" title="Copy code"><i class="far fa-copy" aria-hidden="true"></i><span>Copy</span></button><span class="af-code-status" role="status" aria-live="polite"></span></div><div class="body" dir="ltr"><code>ss -ltn | grep ':3102'</code></div></div>No matching listener should be present before this test. Do not use an occupied port. Keep the sample bound to 127.0.0.1 so the temporary copy is not exposed publicly.<br />
<br />
Check its JavaScript syntax:<br />
<div class="codeblock"><div class="title af-code-title"><span>Code:</span><button type="button" class="af-code-copy" aria-label="Copy code" title="Copy code"><i class="far fa-copy" aria-hidden="true"></i><span>Copy</span></button><span class="af-code-status" role="status" aria-live="polite"></span></div><div class="body" dir="ltr"><code>/www/server/nodejs/v24.21.0/bin/node --check   /www/af-node-restore-20261014/af-node-lab/server.js</code></div></div>Replace the runtime path with your installed version. Real applications may also need dependencies, compilation and test environment configuration. Do not connect a recovery test to production services that could send mail, charge payments or modify live data.<br />
<br />
<span style="font-weight: bold;" class="mycode_b">7. Run the copy and check its response</span><br />
In one SSH session, start it in the foreground as www:<br />
<div class="codeblock"><div class="title af-code-title"><span>Code:</span><button type="button" class="af-code-copy" aria-label="Copy code" title="Copy code"><i class="far fa-copy" aria-hidden="true"></i><span>Copy</span></button><span class="af-code-status" role="status" aria-live="polite"></span></div><div class="body" dir="ltr"><code>sudo runuser -u www -- /www/server/nodejs/v24.21.0/bin/node   /www/af-node-restore-20261014/af-node-lab/server.js</code></div></div>In a second SSH session:<br />
<div class="codeblock"><div class="title af-code-title"><span>Code:</span><button type="button" class="af-code-copy" aria-label="Copy code" title="Copy code"><i class="far fa-copy" aria-hidden="true"></i><span>Copy</span></button><span class="af-code-status" role="status" aria-live="polite"></span></div><div class="body" dir="ltr"><code>curl -i http://127.0.0.1:3102/
curl -I https://node.adminslab.com/</code></div></div>The restored sample should return HTTP 200 and the AdminsForum Node.js Lab page. The live domain should still return 200 independently. We verified the restored response and the live domain during our test.<br />
<br />
When finished, stop the foreground test with Ctrl+C. Our test also stopped its temporary process after validation; the live app remained running. Confirm that the temporary listener has gone before reusing the port.<br />
<br />
<span style="font-weight: bold;" class="mycode_b">8. Record the recovery result</span><br />
Our test result was:<br />
<div class="codeblock"><div class="title af-code-title"><span>Code:</span><button type="button" class="af-code-copy" aria-label="Copy code" title="Copy code"><i class="far fa-copy" aria-hidden="true"></i><span>Copy</span></button><span class="af-code-status" role="status" aria-live="polite"></span></div><div class="body" dir="ltr"><code>server.js file hash: MATCH
package.json file hash: MATCH
yarn.lock file hash: MATCH
Restored app on localhost:3102: EXPECTED PAGE
Live HTTPS website: 200</code></div></div>The archive and isolated restored folder were retained for later inspection. This proves recovery of this small source-based sample, not a full server or database restore.<br />
<br />
<span style="font-weight: bold;" class="mycode_b">9. Before replacing a real deployment</span><br />
Keep the current release and its backup, restore any database consistently, verify dependencies and secrets, then plan the switch and rollback. Use aaPanel to configure the intended project directory and runtime only after the recovery copy passes its checks. Repeat response tests after the change. This guide deliberately stops before a live cutover.<br />
<br />
<span style="font-weight: bold;" class="mycode_b">Related guide:</span> <a href="https://adminsforum.com/Thread-guide-deploy-a-node-js-app-in-aapanel-with-a-domain-and-https" target="_blank" rel="noopener" class="mycode_url">Deploy a Node.js app in aaPanel with a domain and HTTPS</a>.]]></content:encoded>
		</item>
		<item>
			<title><![CDATA[Verify a Full WordPress Backup Restore in aaPanel]]></title>
			<link>https://adminsforum.com/Thread-guide-verify-a-full-wordpress-backup-restore-in-aapanel</link>
			<pubDate>Tue, 13 Oct 2026 11:52:24 +0800</pubDate>
			<dc:creator><![CDATA[<a href="https://adminsforum.com/member.php?action=profile&uid=2">DEV</a>]]></dc:creator>
			<guid isPermaLink="false">https://adminsforum.com/Thread-guide-verify-a-full-wordpress-backup-restore-in-aapanel</guid>
			<description><![CDATA[<span style="font-weight: bold;" class="mycode_b">Quick answer</span><br />
A full WordPress recovery needs both website files and the database. Test the backup in an isolated location before replacing a live site. Our aaPanel backup rehearsal restored 3,935 files with matching hashes, imported 12 database tables and loaded the restored WordPress installation successfully.<br />
<!-- start: postbit_attachments_attachment -->
<br /><!-- start: attachment_icon -->
<img src="https://adminsforum.com/images/attachtypes/image.png" title="JPG Image" border="0" alt=".jpg" />
<!-- end: attachment_icon -->&nbsp;&nbsp;<a href="attachment.php?aid=128" target="_blank" title="">restore-rehearsal-branded-20261013.jpg</a> (Size: 51.34 KB / Downloads: 6)
<!-- end: postbit_attachments_attachment --><br />
This was a private staging rehearsal, not an overwrite of the live WordPress website. It proves the tested archive's file restoration, SQL import and WordPress bootstrap; browser pages, login, email, payment integrations and a production cutover require their own checks.<br />
<br />
<span style="font-weight: bold;" class="mycode_b">1. Choose the correct backup set</span><br />
In the WordPress backup area, identify the site, backup time and archive. Keep the matching database and files together. Download an independent copy and record the intended recovery point so you know which newer changes would be lost in a live rollback.<br />
Our tested archive was wp.adminslab.com_20261012_163830.zip. Its outer ZIP contained meta.json, database.sql.gz and files.zip. That format is specific to this lab backup; inspect your own archive rather than assuming every aaPanel backup has the same layout.<br />
A website ZIP containing uploads and PHP files is not automatically a database backup. A database dump does not contain all your themes, plugins or uploaded images.<br />
<br />
<span style="font-weight: bold;" class="mycode_b">2. Keep the rehearsal outside the public website</span><br />
Use a new private working directory outside /www/wwwroot, with restrictive permissions. Do not extract wp-config.php or SQL dumps into a public URL just for convenience. Confirm the target directory is empty before extraction so an older test is not silently overwritten.<br />
Our working copy was under a root-owned private directory with mode 0700. Credential files used mode 0600. No new public website or hostname was created for this rehearsal.<br />
Do not use your live document root or live database name as a staging destination.<br />
<br />
<span style="font-weight: bold;" class="mycode_b">3. Check both archive layers</span><br />
Validate the outer ZIP, then the nested files.zip and the compressed SQL member. Our outer archive had three members, and the nested file archive had 4,423 entries including directories. Both ZIP integrity checks passed.<br />
You can inspect an archive with Python's built-in ZIP tools:<br />
<div class="codeblock"><div class="title af-code-title"><span>Code:</span><button type="button" class="af-code-copy" aria-label="Copy code" title="Copy code"><i class="far fa-copy" aria-hidden="true"></i><span>Copy</span></button><span class="af-code-status" role="status" aria-live="polite"></span></div><div class="body" dir="ltr"><code>python3 -m zipfile -l /path/to/your-backup.zip
python3 -m zipfile -t /path/to/your-backup.zip</code></div></div>Do not treat a valid ZIP checksum as proof that WordPress can be restored. It only verifies that the stored archive entries are readable without that integrity error.<br />
Our extraction also checked that every destination stayed inside the private staging folder and rejected symlink entries needing review. Inspect the archive paths before extracting an unfamiliar backup.<br />
<br />
<span style="font-weight: bold;" class="mycode_b">4. Restore the website files into staging</span><br />
Extract the outer package into the private work area. Extract files.zip into a separate empty staging directory. Check that the expected WordPress structure is present: wp-admin, wp-includes, wp-content, wp-load.php and wp-config.php.<br />
Keep the archive unchanged. We compared each extracted regular file against its archive member using SHA-256 before editing staging configuration; 3,935 file hashes matched. Directories are not counted as regular files in that result.<br />
For a smaller manual spot check, compare several important files and an uploaded image, but label that as a sample. It is not the same as the full file comparison used in this rehearsal.<br />
<br />
<span style="font-weight: bold;" class="mycode_b">5. Create a separate restore database</span><br />
Use a new clearly named temporary database. Our database was af_restore_verify_20261013, separate from the active WordPress database. Confirm it does not already exist before creating it.<br />
Use existing authorized database-administration access for the import, and keep credentials out of command-line arguments, screenshots and forum posts. A private MySQL client option file is one approach:<br />
<div class="codeblock"><div class="title af-code-title"><span>Code:</span><button type="button" class="af-code-copy" aria-label="Copy code" title="Copy code"><i class="far fa-copy" aria-hidden="true"></i><span>Copy</span></button><span class="af-code-status" role="status" aria-live="polite"></span></div><div class="body" dir="ltr"><code>[client]
user=YOUR_AUTHORIZED_DATABASE_ADMIN
password="YOUR_EXISTING_PRIVATE_PASSWORD"
host=localhost</code></div></div>Store it in a private administration directory with permissions 0600. Do not paste real credentials into this article's examples.<br />
Before importing, inspect the dump for database-switching statements such as USE, CREATE DATABASE or DROP DATABASE. Our dump had none; the importer explicitly targeted the temporary database. Stop and review a dump that would redirect the import to another database.<br />
A representative import uses the private option file and the chosen staging database:<br />
<div class="codeblock"><div class="title af-code-title"><span>Code:</span><button type="button" class="af-code-copy" aria-label="Copy code" title="Copy code"><i class="far fa-copy" aria-hidden="true"></i><span>Copy</span></button><span class="af-code-status" role="status" aria-live="polite"></span></div><div class="body" dir="ltr"><code>set -o pipefail
gunzip -c /private/work/database.sql.gz | mysql --defaults-extra-file=/root/wp-restore-auth.cnf YOUR_STAGING_DATABASE</code></div></div>Replace every example path and name with your verified staging values. Check both decompression and import exit status. Do not run this against the live database while rehearsing.<br />
Our import succeeded and the staging database contained 12 tables.<br />
<br />
<span style="font-weight: bold;" class="mycode_b">6. Point only the staging configuration to that database</span><br />
Edit the staging copy of wp-config.php so DB_NAME, DB_USER, DB_PASSWORD and DB_HOST refer to the intended private restore database and authorized identity. Verify the file you are editing is the copy, not the live configuration.<br />
Preserve the table prefix from the backup. A correct database name with the wrong prefix can make a restored site appear uninstalled or empty.<br />
Use a restricted application database identity before exposing a restored site publicly. The lab's temporary administration identity was used only inside an inaccessible private rehearsal; it is not a recommendation to put a database root account into a public website.<br />
Check PHP syntax with the interpreter appropriate for the restored site. Resolve any configuration error before loading WordPress.<br />
<br />
<span style="font-weight: bold;" class="mycode_b">7. Load WordPress without scheduling or shared-cache side effects</span><br />
Our test runner disabled traffic-triggered cron, persistent Redis access and early page-cache loading for the private copy before loading its wp-load.php. It then confirmed the configured database was the staging database and queried the restored posts and options tables.<br />
The bootstrap passed. The snapshot contained 9 post-table rows and 163 option-table rows. These counts are evidence from that backup, not numbers every WordPress installation should have.<br />
Keep scheduled jobs and external integrations isolated while rehearsing. A restored copy should not take over the live site's cache namespace or run duplicate live schedules.<br />
<br />
<span style="font-weight: bold;" class="mycode_b">8. Add browser and application checks before cutover</span><br />
If you later make a private browser-accessible staging site, verify its URL settings, HTTPS, login, images, permalinks, forms, plugins and essential application functions. Moving to a different domain may require a WordPress-aware URL migration; a blind SQL text replacement can damage serialized values.<br />
Before a live restore, take a fresh rollback copy of the current files and database, plan a maintenance window and document the expected data-loss interval. The rehearsal did not perform that cutover.<br />
<br />
<span style="font-weight: bold;" class="mycode_b">Do not rely on a success notification alone</span><br />
An earlier lab check of the native WP Toolkit Restore action reported success, but test changes remained. That native behavior has not been repaired or revalidated by this manual rehearsal. The independently tested archive restore is the verified result here.<br />
After any actual restore, confirm a known file and database value match the selected backup point. Checking only that the home page loads can miss a partial restore.<br />
<br />
<span style="font-weight: bold;" class="mycode_b">Final lab result</span><ul class="mycode_list"><li>Outer and nested archives were readable and passed integrity checks.<br />
</li>
<li>3,935 extracted regular files matched their archive hashes before configuration changes.<br />
</li>
<li>The SQL imported into a separate private database with 12 tables.<br />
</li>
<li>The restored WordPress copy loaded and its data tables were readable.<br />
</li>
<li>The current public website and its active database were not overwritten.<br />
</li>
</ul>
The private rehearsal copy remains available for review. Keep backup and credential material private throughout cleanup and recovery.<br />
<br />
<span style="font-weight: bold;" class="mycode_b">Reference:</span> <a href="https://developer.wordpress.org/advanced-administration/security/backup/" target="_blank" rel="noopener" class="mycode_url">WordPress backup documentation</a>. © AdminsForum.]]></description>
			<content:encoded><![CDATA[<span style="font-weight: bold;" class="mycode_b">Quick answer</span><br />
A full WordPress recovery needs both website files and the database. Test the backup in an isolated location before replacing a live site. Our aaPanel backup rehearsal restored 3,935 files with matching hashes, imported 12 database tables and loaded the restored WordPress installation successfully.<br />
<!-- start: postbit_attachments_attachment -->
<br /><!-- start: attachment_icon -->
<img src="https://adminsforum.com/images/attachtypes/image.png" title="JPG Image" border="0" alt=".jpg" />
<!-- end: attachment_icon -->&nbsp;&nbsp;<a href="attachment.php?aid=128" target="_blank" title="">restore-rehearsal-branded-20261013.jpg</a> (Size: 51.34 KB / Downloads: 6)
<!-- end: postbit_attachments_attachment --><br />
This was a private staging rehearsal, not an overwrite of the live WordPress website. It proves the tested archive's file restoration, SQL import and WordPress bootstrap; browser pages, login, email, payment integrations and a production cutover require their own checks.<br />
<br />
<span style="font-weight: bold;" class="mycode_b">1. Choose the correct backup set</span><br />
In the WordPress backup area, identify the site, backup time and archive. Keep the matching database and files together. Download an independent copy and record the intended recovery point so you know which newer changes would be lost in a live rollback.<br />
Our tested archive was wp.adminslab.com_20261012_163830.zip. Its outer ZIP contained meta.json, database.sql.gz and files.zip. That format is specific to this lab backup; inspect your own archive rather than assuming every aaPanel backup has the same layout.<br />
A website ZIP containing uploads and PHP files is not automatically a database backup. A database dump does not contain all your themes, plugins or uploaded images.<br />
<br />
<span style="font-weight: bold;" class="mycode_b">2. Keep the rehearsal outside the public website</span><br />
Use a new private working directory outside /www/wwwroot, with restrictive permissions. Do not extract wp-config.php or SQL dumps into a public URL just for convenience. Confirm the target directory is empty before extraction so an older test is not silently overwritten.<br />
Our working copy was under a root-owned private directory with mode 0700. Credential files used mode 0600. No new public website or hostname was created for this rehearsal.<br />
Do not use your live document root or live database name as a staging destination.<br />
<br />
<span style="font-weight: bold;" class="mycode_b">3. Check both archive layers</span><br />
Validate the outer ZIP, then the nested files.zip and the compressed SQL member. Our outer archive had three members, and the nested file archive had 4,423 entries including directories. Both ZIP integrity checks passed.<br />
You can inspect an archive with Python's built-in ZIP tools:<br />
<div class="codeblock"><div class="title af-code-title"><span>Code:</span><button type="button" class="af-code-copy" aria-label="Copy code" title="Copy code"><i class="far fa-copy" aria-hidden="true"></i><span>Copy</span></button><span class="af-code-status" role="status" aria-live="polite"></span></div><div class="body" dir="ltr"><code>python3 -m zipfile -l /path/to/your-backup.zip
python3 -m zipfile -t /path/to/your-backup.zip</code></div></div>Do not treat a valid ZIP checksum as proof that WordPress can be restored. It only verifies that the stored archive entries are readable without that integrity error.<br />
Our extraction also checked that every destination stayed inside the private staging folder and rejected symlink entries needing review. Inspect the archive paths before extracting an unfamiliar backup.<br />
<br />
<span style="font-weight: bold;" class="mycode_b">4. Restore the website files into staging</span><br />
Extract the outer package into the private work area. Extract files.zip into a separate empty staging directory. Check that the expected WordPress structure is present: wp-admin, wp-includes, wp-content, wp-load.php and wp-config.php.<br />
Keep the archive unchanged. We compared each extracted regular file against its archive member using SHA-256 before editing staging configuration; 3,935 file hashes matched. Directories are not counted as regular files in that result.<br />
For a smaller manual spot check, compare several important files and an uploaded image, but label that as a sample. It is not the same as the full file comparison used in this rehearsal.<br />
<br />
<span style="font-weight: bold;" class="mycode_b">5. Create a separate restore database</span><br />
Use a new clearly named temporary database. Our database was af_restore_verify_20261013, separate from the active WordPress database. Confirm it does not already exist before creating it.<br />
Use existing authorized database-administration access for the import, and keep credentials out of command-line arguments, screenshots and forum posts. A private MySQL client option file is one approach:<br />
<div class="codeblock"><div class="title af-code-title"><span>Code:</span><button type="button" class="af-code-copy" aria-label="Copy code" title="Copy code"><i class="far fa-copy" aria-hidden="true"></i><span>Copy</span></button><span class="af-code-status" role="status" aria-live="polite"></span></div><div class="body" dir="ltr"><code>[client]
user=YOUR_AUTHORIZED_DATABASE_ADMIN
password="YOUR_EXISTING_PRIVATE_PASSWORD"
host=localhost</code></div></div>Store it in a private administration directory with permissions 0600. Do not paste real credentials into this article's examples.<br />
Before importing, inspect the dump for database-switching statements such as USE, CREATE DATABASE or DROP DATABASE. Our dump had none; the importer explicitly targeted the temporary database. Stop and review a dump that would redirect the import to another database.<br />
A representative import uses the private option file and the chosen staging database:<br />
<div class="codeblock"><div class="title af-code-title"><span>Code:</span><button type="button" class="af-code-copy" aria-label="Copy code" title="Copy code"><i class="far fa-copy" aria-hidden="true"></i><span>Copy</span></button><span class="af-code-status" role="status" aria-live="polite"></span></div><div class="body" dir="ltr"><code>set -o pipefail
gunzip -c /private/work/database.sql.gz | mysql --defaults-extra-file=/root/wp-restore-auth.cnf YOUR_STAGING_DATABASE</code></div></div>Replace every example path and name with your verified staging values. Check both decompression and import exit status. Do not run this against the live database while rehearsing.<br />
Our import succeeded and the staging database contained 12 tables.<br />
<br />
<span style="font-weight: bold;" class="mycode_b">6. Point only the staging configuration to that database</span><br />
Edit the staging copy of wp-config.php so DB_NAME, DB_USER, DB_PASSWORD and DB_HOST refer to the intended private restore database and authorized identity. Verify the file you are editing is the copy, not the live configuration.<br />
Preserve the table prefix from the backup. A correct database name with the wrong prefix can make a restored site appear uninstalled or empty.<br />
Use a restricted application database identity before exposing a restored site publicly. The lab's temporary administration identity was used only inside an inaccessible private rehearsal; it is not a recommendation to put a database root account into a public website.<br />
Check PHP syntax with the interpreter appropriate for the restored site. Resolve any configuration error before loading WordPress.<br />
<br />
<span style="font-weight: bold;" class="mycode_b">7. Load WordPress without scheduling or shared-cache side effects</span><br />
Our test runner disabled traffic-triggered cron, persistent Redis access and early page-cache loading for the private copy before loading its wp-load.php. It then confirmed the configured database was the staging database and queried the restored posts and options tables.<br />
The bootstrap passed. The snapshot contained 9 post-table rows and 163 option-table rows. These counts are evidence from that backup, not numbers every WordPress installation should have.<br />
Keep scheduled jobs and external integrations isolated while rehearsing. A restored copy should not take over the live site's cache namespace or run duplicate live schedules.<br />
<br />
<span style="font-weight: bold;" class="mycode_b">8. Add browser and application checks before cutover</span><br />
If you later make a private browser-accessible staging site, verify its URL settings, HTTPS, login, images, permalinks, forms, plugins and essential application functions. Moving to a different domain may require a WordPress-aware URL migration; a blind SQL text replacement can damage serialized values.<br />
Before a live restore, take a fresh rollback copy of the current files and database, plan a maintenance window and document the expected data-loss interval. The rehearsal did not perform that cutover.<br />
<br />
<span style="font-weight: bold;" class="mycode_b">Do not rely on a success notification alone</span><br />
An earlier lab check of the native WP Toolkit Restore action reported success, but test changes remained. That native behavior has not been repaired or revalidated by this manual rehearsal. The independently tested archive restore is the verified result here.<br />
After any actual restore, confirm a known file and database value match the selected backup point. Checking only that the home page loads can miss a partial restore.<br />
<br />
<span style="font-weight: bold;" class="mycode_b">Final lab result</span><ul class="mycode_list"><li>Outer and nested archives were readable and passed integrity checks.<br />
</li>
<li>3,935 extracted regular files matched their archive hashes before configuration changes.<br />
</li>
<li>The SQL imported into a separate private database with 12 tables.<br />
</li>
<li>The restored WordPress copy loaded and its data tables were readable.<br />
</li>
<li>The current public website and its active database were not overwritten.<br />
</li>
</ul>
The private rehearsal copy remains available for review. Keep backup and credential material private throughout cleanup and recovery.<br />
<br />
<span style="font-weight: bold;" class="mycode_b">Reference:</span> <a href="https://developer.wordpress.org/advanced-administration/security/backup/" target="_blank" rel="noopener" class="mycode_url">WordPress backup documentation</a>. © AdminsForum.]]></content:encoded>
		</item>
		<item>
			<title><![CDATA[Verify a WordPress Backup Before Restoring in aaPanel]]></title>
			<link>https://adminsforum.com/Thread-guide-verify-a-wordpress-backup-before-restoring-in-aapanel</link>
			<pubDate>Tue, 13 Oct 2026 00:36:54 +0800</pubDate>
			<dc:creator><![CDATA[<a href="https://adminsforum.com/member.php?action=profile&uid=2">DEV</a>]]></dc:creator>
			<guid isPermaLink="false">https://adminsforum.com/Thread-guide-verify-a-wordpress-backup-before-restoring-in-aapanel</guid>
			<description><![CDATA[<span style="font-weight: bold;" class="mycode_b">Quick answer</span><br />
A backup job finishing successfully proves that the panel created a backup, not that your website can be recovered. Before relying on a WordPress backup, confirm its site and date, check the archive components, preserve another private copy and test restoration on an isolated site.<br />
<br />
This guide uses a real full backup from our AdminsForum lab: aaPanel 8.0.6, WordPress 7.1.3 and a root-installed WP Toolkit site. We verified the archive and compression checks on 12 October 2026. It is a verification walkthrough, not a claim that a completed restore was proven.<br />
<br />
<span style="font-weight: bold;" class="mycode_b">1. Create a current full backup</span><br />
Open <span style="font-weight: bold;" class="mycode_b">WP Toolkit</span>, find the correct domain and click its <span style="font-weight: bold;" class="mycode_b">Backup / Restore</span> entry. Check that the configured backup type includes both files and database, then start the backup and wait for the job to finish.<br />
<br />
Our task displayed <span style="font-weight: bold;" class="mycode_b">1 success, 0 failed</span>. If yours fails, investigate that job before testing restoration. See <a href="https://adminsforum.com/Thread-guide-back-up-wordpress-with-aapanel-wp-toolkit" target="_blank" rel="noopener" class="mycode_url">the backup creation walkthrough</a> for the initial panel steps.<br />
<!-- start: postbit_attachments_attachment -->
<br /><!-- start: attachment_icon -->
<img src="https://adminsforum.com/images/attachtypes/image.png" title="JPG Image" border="0" alt=".jpg" />
<!-- end: attachment_icon -->&nbsp;&nbsp;<a href="attachment.php?aid=80" target="_blank" title="">wp-backup-check-completed-branded-20261012.jpg</a> (Size: 107.92 KB / Downloads: 8)
<!-- end: postbit_attachments_attachment --><br />
<br />
<span style="font-weight: bold;" class="mycode_b">2. Identify the exact archive</span><br />
In the backup list, check the domain, backup time, file size, backup type and storage location. Do not select an older archive just because it is first in a downloaded folder.<br />
<br />
Our selected entry was:<ul class="mycode_list"><li>File: <span style="font-weight: bold;" class="mycode_b">wp.adminslab.com_20261012_153210.zip</span><br />
</li>
<li>Size displayed by aaPanel: <span style="font-weight: bold;" class="mycode_b">41.13 MB</span><br />
</li>
<li>Type: <span style="font-weight: bold;" class="mycode_b">Full Backup</span><br />
</li>
<li>Storage: <span style="font-weight: bold;" class="mycode_b">Local Server</span><br />
</li>
</ul>
<!-- start: postbit_attachments_attachment -->
<br /><!-- start: attachment_icon -->
<img src="https://adminsforum.com/images/attachtypes/image.png" title="JPG Image" border="0" alt=".jpg" />
<!-- end: attachment_icon -->&nbsp;&nbsp;<a href="attachment.php?aid=81" target="_blank" title="">wp-backup-check-list-branded-20261012.jpg</a> (Size: 96.98 KB / Downloads: 9)
<!-- end: postbit_attachments_attachment --><br />
<br />
The panel's displayed backup time can use a different timezone from a timestamp embedded in the filename. Record the exact filename and check the selected site's identity. The warning <span style="font-weight: bold;" class="mycode_b">Subsites not included</span> also matters: a backup of the parent site is not proof that every separate subsite has been captured.<br />
<br />
<span style="font-weight: bold;" class="mycode_b">3. Preserve a private copy</span><br />
Keep the original archive while you investigate. We made a second private copy and confirmed its SHA-256 matched the original. That second copy was on the same lab VPS: it protects against accidentally changing the original during testing, but not against losing the server.<br />
<br />
For disaster recovery, keep a verified copy in separate storage or on another machine. Do not put backups in a public website directory, attach SQL dumps to support posts, or share archive contents that include wp-config.php or database credentials.<br />
<br />
<span style="font-weight: bold;" class="mycode_b">4. Check the archive without restoring it</span><br />
Our full-backup ZIP contained <span style="font-weight: bold;" class="mycode_b">meta.json</span>, <span style="font-weight: bold;" class="mycode_b">database.sql.gz</span> and <span style="font-weight: bold;" class="mycode_b">files.zip</span>. We checked the outer ZIP, decompressed the SQL gzip, tested the nested files ZIP and confirmed wp-config.php was included.<br />
<br />
The following read-only example was also tested against this archive. Open the aaPanel Terminal and change the p = Path(...) line to your actual backup file before running it. It needs Python 3 and its standard library; it does not extract files into your website, import SQL or modify the backup.<br />
<br />
<div class="codeblock"><div class="title af-code-title"><span>Code:</span><button type="button" class="af-code-copy" aria-label="Copy code" title="Copy code"><i class="far fa-copy" aria-hidden="true"></i><span>Copy</span></button><span class="af-code-status" role="status" aria-live="polite"></span></div><div class="body" dir="ltr"><code>python3 - &lt;&lt;'PY'
from pathlib import Path
import gzip, io, json, zipfile
p = Path('/www/backup/wordpress/wp.adminslab.com_20261012_153210.zip')
if not p.is_file():
    raise SystemExit('STOP: backup file not found')
with zipfile.ZipFile(p) as archive:
    if archive.testzip() is not None:
        raise SystemExit('STOP: outer ZIP integrity failed')
    required = {'meta.json', 'database.sql.gz', 'files.zip'}
    if not required.issubset(archive.namelist()):
        raise SystemExit('STOP: expected full-backup components missing')
    meta = json.loads(archive.read('meta.json'))
    print('Backup domain:', meta.get('domain'))
    print('Backup site root:', meta.get('site_path'))
    sql = gzip.decompress(archive.read('database.sql.gz'))
    if not sql:
        raise SystemExit('STOP: SQL data is empty')
    print('SQL compression and non-empty data: PASS')
    with zipfile.ZipFile(io.BytesIO(archive.read('files.zip'))) as files:
        if files.testzip() is not None:
            raise SystemExit('STOP: nested files ZIP integrity failed')
        if not any(n.endswith('wp-config.php') for n in files.namelist()):
            raise SystemExit('STOP: wp-config.php missing')
    print('Files ZIP integrity and wp-config.php presence: PASS')
print('Integrity checks finished. A restore test is still required.')
PY</code></div></div><br />
This example matches the archive layout observed in our aaPanel version. A different backup format needs a different check; a missing component should be investigated rather than renamed to make the script pass. It loads the compressed components into memory, so for large backups use an appropriate streaming/offline verification process instead of copying this small-lab example blindly.<br />
<br />
<!-- start: postbit_attachments_attachment -->
<br /><!-- start: attachment_icon -->
<img src="https://adminsforum.com/images/attachtypes/image.png" title="JPG Image" border="0" alt=".jpg" />
<!-- end: attachment_icon -->&nbsp;&nbsp;<a href="attachment.php?aid=82" target="_blank" title="">wp-backup-check-integrity-branded-20261012.jpg</a> (Size: 40.97 KB / Downloads: 8)
<!-- end: postbit_attachments_attachment --><br />
<br />
<span style="font-weight: bold;" class="mycode_b">Read the result carefully:</span><ul class="mycode_list"><li>The domain and site root should describe the website you intended to back up.<br />
</li>
<li>ZIP integrity checks detect archive corruption; they do not prove the application data is complete or safe.<br />
</li>
<li>Successful SQL gzip decompression and non-empty data do not prove that the SQL will import successfully or contain every required table.<br />
</li>
<li>wp-config.php being present confirms inclusion of that file, not that its database settings match the restore target.<br />
</li>
</ul>
<br />
<span style="font-weight: bold;" class="mycode_b">5. Test recovery on an isolated site</span><br />
Use a disposable staging environment and preserve its current state before overwriting it. Keep production traffic, outgoing email and scheduled jobs out of the recovery test so a copied website does not send duplicate messages or run live integrations.<br />
<br />
Record something that must be recovered from the backup: for example an existing test file's contents, a draft's content, an uploaded image and a harmless database setting. Make a controlled change after the backup, then perform the staging restore through the appropriate restore workflow.<br />
<br />
Afterward, independently check both files and database. Open the restored homepage and a deep page, sign in to WordPress, inspect media and confirm the chosen pre-backup state returned. A page loading alone is not enough.<br />
<br />
<span style="font-weight: bold;" class="mycode_b">A caution from our own test</span><br />
In a separate restore test on this lab, WP Toolkit returned a success response, but a changed backed-up file and a disposable database marker remained afterward. We did not count that as a verified recovery. We have not established the cause or claimed that the result applies to other servers or versions. The disposable markers were removed and our private backup was preserved.<br />
<br />
Extra files created after a backup can also remain in an overwrite-style restore. Their presence alone is not decisive: check an existing backed-up file and a database value as well.<br />
<br />
<span style="font-weight: bold;" class="mycode_b">If any check fails</span><ul class="mycode_list"><li>Stop before overwriting production or deleting older backups.<br />
</li>
<li>Confirm the intended backup filename, domain, site root and database target.<br />
</li>
<li>Review the backup/restore task result and relevant errors; redact credentials before sharing diagnostics.<br />
</li>
<li>Keep the original archive and try recovery in an isolated environment before relying on it.<br />
</li>
</ul>
<br />
<span style="font-weight: bold;" class="mycode_b">What this walkthrough verified</span><br />
The full backup completed, archive checks passed, SQL gzip data decompressed, the nested files ZIP contained wp-config.php, and a matching private safety copy was kept. Successful end-to-end recovery was not verified; that remains a separate requirement.<br />
<br />
Reference: <a href="https://www.aapanel.com/docs/Function/WPToolkit-Local.html" target="_blank" rel="noopener" class="mycode_url">aaPanel WP Toolkit documentation</a>. Screenshots are original AdminsForum lab captures.]]></description>
			<content:encoded><![CDATA[<span style="font-weight: bold;" class="mycode_b">Quick answer</span><br />
A backup job finishing successfully proves that the panel created a backup, not that your website can be recovered. Before relying on a WordPress backup, confirm its site and date, check the archive components, preserve another private copy and test restoration on an isolated site.<br />
<br />
This guide uses a real full backup from our AdminsForum lab: aaPanel 8.0.6, WordPress 7.1.3 and a root-installed WP Toolkit site. We verified the archive and compression checks on 12 October 2026. It is a verification walkthrough, not a claim that a completed restore was proven.<br />
<br />
<span style="font-weight: bold;" class="mycode_b">1. Create a current full backup</span><br />
Open <span style="font-weight: bold;" class="mycode_b">WP Toolkit</span>, find the correct domain and click its <span style="font-weight: bold;" class="mycode_b">Backup / Restore</span> entry. Check that the configured backup type includes both files and database, then start the backup and wait for the job to finish.<br />
<br />
Our task displayed <span style="font-weight: bold;" class="mycode_b">1 success, 0 failed</span>. If yours fails, investigate that job before testing restoration. See <a href="https://adminsforum.com/Thread-guide-back-up-wordpress-with-aapanel-wp-toolkit" target="_blank" rel="noopener" class="mycode_url">the backup creation walkthrough</a> for the initial panel steps.<br />
<!-- start: postbit_attachments_attachment -->
<br /><!-- start: attachment_icon -->
<img src="https://adminsforum.com/images/attachtypes/image.png" title="JPG Image" border="0" alt=".jpg" />
<!-- end: attachment_icon -->&nbsp;&nbsp;<a href="attachment.php?aid=80" target="_blank" title="">wp-backup-check-completed-branded-20261012.jpg</a> (Size: 107.92 KB / Downloads: 8)
<!-- end: postbit_attachments_attachment --><br />
<br />
<span style="font-weight: bold;" class="mycode_b">2. Identify the exact archive</span><br />
In the backup list, check the domain, backup time, file size, backup type and storage location. Do not select an older archive just because it is first in a downloaded folder.<br />
<br />
Our selected entry was:<ul class="mycode_list"><li>File: <span style="font-weight: bold;" class="mycode_b">wp.adminslab.com_20261012_153210.zip</span><br />
</li>
<li>Size displayed by aaPanel: <span style="font-weight: bold;" class="mycode_b">41.13 MB</span><br />
</li>
<li>Type: <span style="font-weight: bold;" class="mycode_b">Full Backup</span><br />
</li>
<li>Storage: <span style="font-weight: bold;" class="mycode_b">Local Server</span><br />
</li>
</ul>
<!-- start: postbit_attachments_attachment -->
<br /><!-- start: attachment_icon -->
<img src="https://adminsforum.com/images/attachtypes/image.png" title="JPG Image" border="0" alt=".jpg" />
<!-- end: attachment_icon -->&nbsp;&nbsp;<a href="attachment.php?aid=81" target="_blank" title="">wp-backup-check-list-branded-20261012.jpg</a> (Size: 96.98 KB / Downloads: 9)
<!-- end: postbit_attachments_attachment --><br />
<br />
The panel's displayed backup time can use a different timezone from a timestamp embedded in the filename. Record the exact filename and check the selected site's identity. The warning <span style="font-weight: bold;" class="mycode_b">Subsites not included</span> also matters: a backup of the parent site is not proof that every separate subsite has been captured.<br />
<br />
<span style="font-weight: bold;" class="mycode_b">3. Preserve a private copy</span><br />
Keep the original archive while you investigate. We made a second private copy and confirmed its SHA-256 matched the original. That second copy was on the same lab VPS: it protects against accidentally changing the original during testing, but not against losing the server.<br />
<br />
For disaster recovery, keep a verified copy in separate storage or on another machine. Do not put backups in a public website directory, attach SQL dumps to support posts, or share archive contents that include wp-config.php or database credentials.<br />
<br />
<span style="font-weight: bold;" class="mycode_b">4. Check the archive without restoring it</span><br />
Our full-backup ZIP contained <span style="font-weight: bold;" class="mycode_b">meta.json</span>, <span style="font-weight: bold;" class="mycode_b">database.sql.gz</span> and <span style="font-weight: bold;" class="mycode_b">files.zip</span>. We checked the outer ZIP, decompressed the SQL gzip, tested the nested files ZIP and confirmed wp-config.php was included.<br />
<br />
The following read-only example was also tested against this archive. Open the aaPanel Terminal and change the p = Path(...) line to your actual backup file before running it. It needs Python 3 and its standard library; it does not extract files into your website, import SQL or modify the backup.<br />
<br />
<div class="codeblock"><div class="title af-code-title"><span>Code:</span><button type="button" class="af-code-copy" aria-label="Copy code" title="Copy code"><i class="far fa-copy" aria-hidden="true"></i><span>Copy</span></button><span class="af-code-status" role="status" aria-live="polite"></span></div><div class="body" dir="ltr"><code>python3 - &lt;&lt;'PY'
from pathlib import Path
import gzip, io, json, zipfile
p = Path('/www/backup/wordpress/wp.adminslab.com_20261012_153210.zip')
if not p.is_file():
    raise SystemExit('STOP: backup file not found')
with zipfile.ZipFile(p) as archive:
    if archive.testzip() is not None:
        raise SystemExit('STOP: outer ZIP integrity failed')
    required = {'meta.json', 'database.sql.gz', 'files.zip'}
    if not required.issubset(archive.namelist()):
        raise SystemExit('STOP: expected full-backup components missing')
    meta = json.loads(archive.read('meta.json'))
    print('Backup domain:', meta.get('domain'))
    print('Backup site root:', meta.get('site_path'))
    sql = gzip.decompress(archive.read('database.sql.gz'))
    if not sql:
        raise SystemExit('STOP: SQL data is empty')
    print('SQL compression and non-empty data: PASS')
    with zipfile.ZipFile(io.BytesIO(archive.read('files.zip'))) as files:
        if files.testzip() is not None:
            raise SystemExit('STOP: nested files ZIP integrity failed')
        if not any(n.endswith('wp-config.php') for n in files.namelist()):
            raise SystemExit('STOP: wp-config.php missing')
    print('Files ZIP integrity and wp-config.php presence: PASS')
print('Integrity checks finished. A restore test is still required.')
PY</code></div></div><br />
This example matches the archive layout observed in our aaPanel version. A different backup format needs a different check; a missing component should be investigated rather than renamed to make the script pass. It loads the compressed components into memory, so for large backups use an appropriate streaming/offline verification process instead of copying this small-lab example blindly.<br />
<br />
<!-- start: postbit_attachments_attachment -->
<br /><!-- start: attachment_icon -->
<img src="https://adminsforum.com/images/attachtypes/image.png" title="JPG Image" border="0" alt=".jpg" />
<!-- end: attachment_icon -->&nbsp;&nbsp;<a href="attachment.php?aid=82" target="_blank" title="">wp-backup-check-integrity-branded-20261012.jpg</a> (Size: 40.97 KB / Downloads: 8)
<!-- end: postbit_attachments_attachment --><br />
<br />
<span style="font-weight: bold;" class="mycode_b">Read the result carefully:</span><ul class="mycode_list"><li>The domain and site root should describe the website you intended to back up.<br />
</li>
<li>ZIP integrity checks detect archive corruption; they do not prove the application data is complete or safe.<br />
</li>
<li>Successful SQL gzip decompression and non-empty data do not prove that the SQL will import successfully or contain every required table.<br />
</li>
<li>wp-config.php being present confirms inclusion of that file, not that its database settings match the restore target.<br />
</li>
</ul>
<br />
<span style="font-weight: bold;" class="mycode_b">5. Test recovery on an isolated site</span><br />
Use a disposable staging environment and preserve its current state before overwriting it. Keep production traffic, outgoing email and scheduled jobs out of the recovery test so a copied website does not send duplicate messages or run live integrations.<br />
<br />
Record something that must be recovered from the backup: for example an existing test file's contents, a draft's content, an uploaded image and a harmless database setting. Make a controlled change after the backup, then perform the staging restore through the appropriate restore workflow.<br />
<br />
Afterward, independently check both files and database. Open the restored homepage and a deep page, sign in to WordPress, inspect media and confirm the chosen pre-backup state returned. A page loading alone is not enough.<br />
<br />
<span style="font-weight: bold;" class="mycode_b">A caution from our own test</span><br />
In a separate restore test on this lab, WP Toolkit returned a success response, but a changed backed-up file and a disposable database marker remained afterward. We did not count that as a verified recovery. We have not established the cause or claimed that the result applies to other servers or versions. The disposable markers were removed and our private backup was preserved.<br />
<br />
Extra files created after a backup can also remain in an overwrite-style restore. Their presence alone is not decisive: check an existing backed-up file and a database value as well.<br />
<br />
<span style="font-weight: bold;" class="mycode_b">If any check fails</span><ul class="mycode_list"><li>Stop before overwriting production or deleting older backups.<br />
</li>
<li>Confirm the intended backup filename, domain, site root and database target.<br />
</li>
<li>Review the backup/restore task result and relevant errors; redact credentials before sharing diagnostics.<br />
</li>
<li>Keep the original archive and try recovery in an isolated environment before relying on it.<br />
</li>
</ul>
<br />
<span style="font-weight: bold;" class="mycode_b">What this walkthrough verified</span><br />
The full backup completed, archive checks passed, SQL gzip data decompressed, the nested files ZIP contained wp-config.php, and a matching private safety copy was kept. Successful end-to-end recovery was not verified; that remains a separate requirement.<br />
<br />
Reference: <a href="https://www.aapanel.com/docs/Function/WPToolkit-Local.html" target="_blank" rel="noopener" class="mycode_url">aaPanel WP Toolkit documentation</a>. Screenshots are original AdminsForum lab captures.]]></content:encoded>
		</item>
		<item>
			<title><![CDATA[Schedule Automatic MySQL Database Backups in aaPanel]]></title>
			<link>https://adminsforum.com/Thread-guide-schedule-automatic-mysql-database-backups-in-aapanel</link>
			<pubDate>Mon, 12 Oct 2026 11:10:41 +0800</pubDate>
			<dc:creator><![CDATA[<a href="https://adminsforum.com/member.php?action=profile&uid=2">DEV</a>]]></dc:creator>
			<guid isPermaLink="false">https://adminsforum.com/Thread-guide-schedule-automatic-mysql-database-backups-in-aapanel</guid>
			<description><![CDATA[<span style="font-weight: bold;" class="mycode_b">Quick answer</span><br />
Open Cron → Backup Database, choose the MySQL database type and your specific database, then set a daily time, destination and retention count. Click Add Task, use Execute for the first test, and read the Log. Check the resulting SQL archive before trusting future runs.<br />
<br />
<span style="font-weight: bold;" class="mycode_b">Tested result</span><br />
On the AdminsForum lab with aaPanel 8.0.6 and MariaDB 10.11, we created Backup Database[af_wordpress]--mysql. The daily schedule was 02:25 on the server's clock, with Local Disk and three retained copies. The first manual run exported a 2.11 MB database and produced a 193.33 KB .sql.gz file. The log reported Successful, and gzip integrity checking passed. We paused this tutorial-only task after testing. The next unattended daily trigger and restoration of this particular dump were not tested.<br />
<br />
<span style="font-weight: bold;" class="mycode_b">1. Find the correct database</span><br />
Open Databases and identify the database used by your application. Do not assume its name matches the domain. For WordPress, the DB_NAME value in its configuration identifies the database, but keep that file private because it also contains credentials.<br />
<br />
If your application uses more than one database, include each required database in the backup plan. Our example selects af_wordpress only. It does not back up the other databases on the server.<br />
<br />
<span style="font-weight: bold;" class="mycode_b">2. Open the backup task form</span><br />
Click Cron in the left-hand menu. Under Add Task, set Task type to Backup Database. In Backup database, select MySQL for this MySQL/MariaDB example. The lab runs MariaDB but aaPanel presents this engine family as MySQL in the task form.<br />
<br />
Use Database to select the required database instead of leaving ALL selected unless every listed database should be included. The task name is generated from your selection.<br />
<br />
<span style="font-weight: bold;" class="mycode_b">3. Choose a time and destination</span><br />
Set Execute cycle to Daily and enter the hour and minute. We used 02:25 so it did not start at the same time as the website-file job. Check the server clock and time zone first. Staggering jobs helps avoid simultaneous compression and database activity, but does not guarantee that file and database backups represent the same instant.<br />
<br />
For this first test we selected Local Disk and kept the latest three copies. Choose a retention count based on available space and how far back you need to recover. Repeated manual executions can also create copies; retention is not automatically equivalent to a number of days.<br />
<br />
<!-- start: postbit_attachments_attachment -->
<br /><!-- start: attachment_icon -->
<img src="https://adminsforum.com/images/attachtypes/image.png" title="JPG Image" border="0" alt=".jpg" />
<!-- end: attachment_icon -->&nbsp;&nbsp;<a href="attachment.php?aid=35" target="_blank" title="">cron-database-settings-20261012.jpg</a> (Size: 209.88 KB / Downloads: 9)
<!-- end: postbit_attachments_attachment --><br />
<span style="font-style: italic;" class="mycode_i">AdminsForum lab: the selected WordPress database, daily schedule, local destination and copy count.</span><br />
<br />
The Backup reminder setting was left at non-receipt. No notification delivery was tested. If you enable alerts later, test the notification channel rather than assuming it works.<br />
<br />
<span style="font-weight: bold;" class="mycode_b">4. Create the task and run it once</span><br />
Click Add Task. Check the new row's database name, Running status, time and destination. Click Execute in that exact row and confirm the prompt. Wait for the export and compression to finish, then read Log or use Refresh log.<br />
<br />
<!-- start: postbit_attachments_attachment -->
<br /><!-- start: attachment_icon -->
<img src="https://adminsforum.com/images/attachtypes/image.png" title="JPG Image" border="0" alt=".jpg" />
<!-- end: attachment_icon -->&nbsp;&nbsp;<a href="attachment.php?aid=36" target="_blank" title="">cron-database-log-20261012.jpg</a> (Size: 254.24 KB / Downloads: 9)
<!-- end: postbit_attachments_attachment --><br />
<span style="font-style: italic;" class="mycode_i">AdminsForum lab: successful database export, compressed size, output path and retention result.</span><br />
<br />
A successful result should identify the database you intended and the location of a non-empty archive. A task being present in the list does not prove a backup was produced.<br />
<br />
Our archive was placed under:<br />
<div class="codeblock"><div class="title af-code-title"><span>Code:</span><button type="button" class="af-code-copy" aria-label="Copy code" title="Copy code"><i class="far fa-copy" aria-hidden="true"></i><span>Copy</span></button><span class="af-code-status" role="status" aria-live="polite"></span></div><div class="body" dir="ltr"><code>/www/backup/database/mysql/crontab_backup/af_wordpress/</code></div></div>The log provided its exact timestamped filename. Your version or storage configuration may use a different path; follow your own log.<br />
<br />
<span style="font-weight: bold;" class="mycode_b">5. Verify the compressed SQL file</span><br />
Find the file using aaPanel Files or your normal secure server-access method. Keep it outside public website directories. A database dump can contain member information, application settings and other private data.<br />
<br />
If you use the terminal, verify gzip integrity without extracting the dump:<br />
<div class="codeblock"><div class="title af-code-title"><span>Code:</span><button type="button" class="af-code-copy" aria-label="Copy code" title="Copy code"><i class="far fa-copy" aria-hidden="true"></i><span>Copy</span></button><span class="af-code-status" role="status" aria-live="polite"></span></div><div class="body" dir="ltr"><code>gzip -t /path/to/your-database.sql.gz &amp;&amp; echo 'Compressed backup integrity OK'</code></div></div>Replace the example path with the real file from your log. We ran this successfully on the lab dump. It confirms that the compressed stream is intact; it does not prove the SQL will import successfully or that every application component can be restored.<br />
<br />
A much smaller compressed file can be normal. Compare with the logged database size and inspect its structure privately when needed. Do not publish SQL contents in a support thread.<br />
<br />
<span style="font-weight: bold;" class="mycode_b">6. Plan an isolated restore test</span><br />
The strongest check is to import a copy into a separate test database and confirm the expected tables and application content. Avoid overwriting the live database just to test a backup. Record the original application configuration and use a separate test site if you need to point an application at the restored database.<br />
<br />
The <a href="https://adminsforum.com/Thread-guide-back-up-and-restore-a-database-in-aapanel-free-edition" target="_blank" rel="noopener" class="mycode_url">database backup and restore guide</a> covers the separate restore workflow. This article tests creation and archive integrity, rather than claiming a restore of the new cron archive.<br />
<br />
<span style="font-weight: bold;" class="mycode_b">7. Keep website files and database backups together</span><br />
A database dump does not include WordPress uploads, themes, plugins or website configuration files. Pair it with a <a href="https://adminsforum.com/Thread-guide-schedule-automatic-website-backups-in-aapanel" target="_blank" rel="noopener" class="mycode_url">scheduled website-file backup</a>.<br />
<br />
For a busy store or other frequently changing application, consider application-supported consistent backups or a brief maintenance period. Two independently timed backup jobs do not automatically guarantee a consistent recovery point.<br />
<br />
<span style="font-weight: bold;" class="mycode_b">8. Keep an off-server copy and check the next run</span><br />
Transfer a copy to protected off-server storage and confirm it can be retrieved. A same-server copy is not enough if the VPS disk or account is lost. Limit who can access the dump and avoid public download links.<br />
<br />
After the first scheduled time passes, inspect Last execute time and Log and confirm a fresh archive exists. A manual Execute test verifies the backup operation, while the scheduled trigger still needs its own check.<br />
<br />
After the lab test, we selected the task checkbox, chose Stop task in the list action menu, clicked Execute and confirmed. The task now shows Stopped. The dump remains available. Enable your real schedule when you intend to keep it operating, and review the results regularly.<br />
<br />
<span style="font-weight: bold;" class="mycode_b">Troubleshooting</span><ul class="mycode_list"><li><span style="font-weight: bold;" class="mycode_b">Access denied during export:</span> check the database connection and the relevant task log. Do not paste passwords into a forum post.<br />
</li>
<li><span style="font-weight: bold;" class="mycode_b">No database in the selector:</span> confirm it is managed by the appropriate aaPanel database connection and review support for that connection type.<br />
</li>
<li><span style="font-weight: bold;" class="mycode_b">Empty or missing archive:</span> inspect the export/compression error and available disk space; a last-execution timestamp alone is insufficient.<br />
</li>
<li><span style="font-weight: bold;" class="mycode_b">Remote database:</span> verify the actual capabilities shown by your aaPanel version. The lab UI warns that remote databases do not support backup tables; our test used a local database.<br />
</li>
<li><span style="font-weight: bold;" class="mycode_b">Scheduled run missed:</span> check Running status, server time, cron service and task logs.<br />
</li>
</ul>
<br />
<span style="font-weight: bold;" class="mycode_b">Completion checklist</span><ul class="mycode_list"><li>Correct application database selected.<br />
</li>
<li>Schedule, destination and retention reviewed.<br />
</li>
<li>First manual export completed with a successful log.<br />
</li>
<li>Compressed SQL archive exists and passed integrity checking.<br />
</li>
<li>Website-file coverage and protected off-server storage included.<br />
</li>
<li>Isolated restore and first unattended run planned and checked.<br />
</li>
</ul>
<br />
<span style="font-weight: bold;" class="mycode_b">Reference:</span> <a href="https://www.aapanel.com/docs/Function/Cron.html" target="_blank" rel="noopener" class="mycode_url">aaPanel official Cron documentation</a>.]]></description>
			<content:encoded><![CDATA[<span style="font-weight: bold;" class="mycode_b">Quick answer</span><br />
Open Cron → Backup Database, choose the MySQL database type and your specific database, then set a daily time, destination and retention count. Click Add Task, use Execute for the first test, and read the Log. Check the resulting SQL archive before trusting future runs.<br />
<br />
<span style="font-weight: bold;" class="mycode_b">Tested result</span><br />
On the AdminsForum lab with aaPanel 8.0.6 and MariaDB 10.11, we created Backup Database[af_wordpress]--mysql. The daily schedule was 02:25 on the server's clock, with Local Disk and three retained copies. The first manual run exported a 2.11 MB database and produced a 193.33 KB .sql.gz file. The log reported Successful, and gzip integrity checking passed. We paused this tutorial-only task after testing. The next unattended daily trigger and restoration of this particular dump were not tested.<br />
<br />
<span style="font-weight: bold;" class="mycode_b">1. Find the correct database</span><br />
Open Databases and identify the database used by your application. Do not assume its name matches the domain. For WordPress, the DB_NAME value in its configuration identifies the database, but keep that file private because it also contains credentials.<br />
<br />
If your application uses more than one database, include each required database in the backup plan. Our example selects af_wordpress only. It does not back up the other databases on the server.<br />
<br />
<span style="font-weight: bold;" class="mycode_b">2. Open the backup task form</span><br />
Click Cron in the left-hand menu. Under Add Task, set Task type to Backup Database. In Backup database, select MySQL for this MySQL/MariaDB example. The lab runs MariaDB but aaPanel presents this engine family as MySQL in the task form.<br />
<br />
Use Database to select the required database instead of leaving ALL selected unless every listed database should be included. The task name is generated from your selection.<br />
<br />
<span style="font-weight: bold;" class="mycode_b">3. Choose a time and destination</span><br />
Set Execute cycle to Daily and enter the hour and minute. We used 02:25 so it did not start at the same time as the website-file job. Check the server clock and time zone first. Staggering jobs helps avoid simultaneous compression and database activity, but does not guarantee that file and database backups represent the same instant.<br />
<br />
For this first test we selected Local Disk and kept the latest three copies. Choose a retention count based on available space and how far back you need to recover. Repeated manual executions can also create copies; retention is not automatically equivalent to a number of days.<br />
<br />
<!-- start: postbit_attachments_attachment -->
<br /><!-- start: attachment_icon -->
<img src="https://adminsforum.com/images/attachtypes/image.png" title="JPG Image" border="0" alt=".jpg" />
<!-- end: attachment_icon -->&nbsp;&nbsp;<a href="attachment.php?aid=35" target="_blank" title="">cron-database-settings-20261012.jpg</a> (Size: 209.88 KB / Downloads: 9)
<!-- end: postbit_attachments_attachment --><br />
<span style="font-style: italic;" class="mycode_i">AdminsForum lab: the selected WordPress database, daily schedule, local destination and copy count.</span><br />
<br />
The Backup reminder setting was left at non-receipt. No notification delivery was tested. If you enable alerts later, test the notification channel rather than assuming it works.<br />
<br />
<span style="font-weight: bold;" class="mycode_b">4. Create the task and run it once</span><br />
Click Add Task. Check the new row's database name, Running status, time and destination. Click Execute in that exact row and confirm the prompt. Wait for the export and compression to finish, then read Log or use Refresh log.<br />
<br />
<!-- start: postbit_attachments_attachment -->
<br /><!-- start: attachment_icon -->
<img src="https://adminsforum.com/images/attachtypes/image.png" title="JPG Image" border="0" alt=".jpg" />
<!-- end: attachment_icon -->&nbsp;&nbsp;<a href="attachment.php?aid=36" target="_blank" title="">cron-database-log-20261012.jpg</a> (Size: 254.24 KB / Downloads: 9)
<!-- end: postbit_attachments_attachment --><br />
<span style="font-style: italic;" class="mycode_i">AdminsForum lab: successful database export, compressed size, output path and retention result.</span><br />
<br />
A successful result should identify the database you intended and the location of a non-empty archive. A task being present in the list does not prove a backup was produced.<br />
<br />
Our archive was placed under:<br />
<div class="codeblock"><div class="title af-code-title"><span>Code:</span><button type="button" class="af-code-copy" aria-label="Copy code" title="Copy code"><i class="far fa-copy" aria-hidden="true"></i><span>Copy</span></button><span class="af-code-status" role="status" aria-live="polite"></span></div><div class="body" dir="ltr"><code>/www/backup/database/mysql/crontab_backup/af_wordpress/</code></div></div>The log provided its exact timestamped filename. Your version or storage configuration may use a different path; follow your own log.<br />
<br />
<span style="font-weight: bold;" class="mycode_b">5. Verify the compressed SQL file</span><br />
Find the file using aaPanel Files or your normal secure server-access method. Keep it outside public website directories. A database dump can contain member information, application settings and other private data.<br />
<br />
If you use the terminal, verify gzip integrity without extracting the dump:<br />
<div class="codeblock"><div class="title af-code-title"><span>Code:</span><button type="button" class="af-code-copy" aria-label="Copy code" title="Copy code"><i class="far fa-copy" aria-hidden="true"></i><span>Copy</span></button><span class="af-code-status" role="status" aria-live="polite"></span></div><div class="body" dir="ltr"><code>gzip -t /path/to/your-database.sql.gz &amp;&amp; echo 'Compressed backup integrity OK'</code></div></div>Replace the example path with the real file from your log. We ran this successfully on the lab dump. It confirms that the compressed stream is intact; it does not prove the SQL will import successfully or that every application component can be restored.<br />
<br />
A much smaller compressed file can be normal. Compare with the logged database size and inspect its structure privately when needed. Do not publish SQL contents in a support thread.<br />
<br />
<span style="font-weight: bold;" class="mycode_b">6. Plan an isolated restore test</span><br />
The strongest check is to import a copy into a separate test database and confirm the expected tables and application content. Avoid overwriting the live database just to test a backup. Record the original application configuration and use a separate test site if you need to point an application at the restored database.<br />
<br />
The <a href="https://adminsforum.com/Thread-guide-back-up-and-restore-a-database-in-aapanel-free-edition" target="_blank" rel="noopener" class="mycode_url">database backup and restore guide</a> covers the separate restore workflow. This article tests creation and archive integrity, rather than claiming a restore of the new cron archive.<br />
<br />
<span style="font-weight: bold;" class="mycode_b">7. Keep website files and database backups together</span><br />
A database dump does not include WordPress uploads, themes, plugins or website configuration files. Pair it with a <a href="https://adminsforum.com/Thread-guide-schedule-automatic-website-backups-in-aapanel" target="_blank" rel="noopener" class="mycode_url">scheduled website-file backup</a>.<br />
<br />
For a busy store or other frequently changing application, consider application-supported consistent backups or a brief maintenance period. Two independently timed backup jobs do not automatically guarantee a consistent recovery point.<br />
<br />
<span style="font-weight: bold;" class="mycode_b">8. Keep an off-server copy and check the next run</span><br />
Transfer a copy to protected off-server storage and confirm it can be retrieved. A same-server copy is not enough if the VPS disk or account is lost. Limit who can access the dump and avoid public download links.<br />
<br />
After the first scheduled time passes, inspect Last execute time and Log and confirm a fresh archive exists. A manual Execute test verifies the backup operation, while the scheduled trigger still needs its own check.<br />
<br />
After the lab test, we selected the task checkbox, chose Stop task in the list action menu, clicked Execute and confirmed. The task now shows Stopped. The dump remains available. Enable your real schedule when you intend to keep it operating, and review the results regularly.<br />
<br />
<span style="font-weight: bold;" class="mycode_b">Troubleshooting</span><ul class="mycode_list"><li><span style="font-weight: bold;" class="mycode_b">Access denied during export:</span> check the database connection and the relevant task log. Do not paste passwords into a forum post.<br />
</li>
<li><span style="font-weight: bold;" class="mycode_b">No database in the selector:</span> confirm it is managed by the appropriate aaPanel database connection and review support for that connection type.<br />
</li>
<li><span style="font-weight: bold;" class="mycode_b">Empty or missing archive:</span> inspect the export/compression error and available disk space; a last-execution timestamp alone is insufficient.<br />
</li>
<li><span style="font-weight: bold;" class="mycode_b">Remote database:</span> verify the actual capabilities shown by your aaPanel version. The lab UI warns that remote databases do not support backup tables; our test used a local database.<br />
</li>
<li><span style="font-weight: bold;" class="mycode_b">Scheduled run missed:</span> check Running status, server time, cron service and task logs.<br />
</li>
</ul>
<br />
<span style="font-weight: bold;" class="mycode_b">Completion checklist</span><ul class="mycode_list"><li>Correct application database selected.<br />
</li>
<li>Schedule, destination and retention reviewed.<br />
</li>
<li>First manual export completed with a successful log.<br />
</li>
<li>Compressed SQL archive exists and passed integrity checking.<br />
</li>
<li>Website-file coverage and protected off-server storage included.<br />
</li>
<li>Isolated restore and first unattended run planned and checked.<br />
</li>
</ul>
<br />
<span style="font-weight: bold;" class="mycode_b">Reference:</span> <a href="https://www.aapanel.com/docs/Function/Cron.html" target="_blank" rel="noopener" class="mycode_url">aaPanel official Cron documentation</a>.]]></content:encoded>
		</item>
		<item>
			<title><![CDATA[Schedule Automatic Website Backups in aaPanel]]></title>
			<link>https://adminsforum.com/Thread-guide-schedule-automatic-website-backups-in-aapanel</link>
			<pubDate>Mon, 12 Oct 2026 11:08:36 +0800</pubDate>
			<dc:creator><![CDATA[<a href="https://adminsforum.com/member.php?action=profile&uid=2">DEV</a>]]></dc:creator>
			<guid isPermaLink="false">https://adminsforum.com/Thread-guide-schedule-automatic-website-backups-in-aapanel</guid>
			<description><![CDATA[<span style="font-weight: bold;" class="mycode_b">Quick answer</span><br />
Open Cron, choose Backup Site, select the website, set a daily time and a backup destination, then click Add Task. Run the task once with Execute and check its Log before trusting the schedule. Website files and the database need separate backup coverage.<br />
<br />
<span style="font-weight: bold;" class="mycode_b">Tested on the AdminsForum lab</span><br />
We created Backup Site[adminslab.com] in aaPanel 8.0.6, scheduled it for 02:10 using the server's clock, selected Local Disk and retained three copies. We manually executed the new task. The log reported Successful and created a 45.78 MB archive from a 119.08 MB document root. The archive passed a tar readability check. We paused the tutorial-only schedule after testing; the archive was preserved. An overnight scheduled execution and a restore of this specific archive were not tested.<br />
<br />
<span style="font-weight: bold;" class="mycode_b">1. Decide what you need to protect</span><br />
For a WordPress or other database-driven website, keep both the document-root files and its database. Files include application code, uploads and configuration. Database content such as posts, settings and accounts is separate.<br />
<br />
Check the site you want to back up, its document-root path and the available disk space first. Keep backup archives outside the public document root. A same-server backup helps with accidental file changes but cannot protect you from losing the entire server.<br />
<br />
<span style="font-weight: bold;" class="mycode_b">2. Select Backup Site</span><br />
Click Cron in the left-hand menu. In the Add Task section, open Task type and choose Backup Site. Select your particular website in Backup site. The lab's task name changed automatically to Backup Site[adminslab.com]. Choose ALL only when you actually want every listed site included.<br />
<br />
<span style="font-weight: bold;" class="mycode_b">3. Set the schedule and retention</span><br />
Choose Daily in Execute cycle, then enter the hour and minute. Our example is 02:10. These fields use the server's clock; check its time zone before treating the value as your local time. Choose a quiet period and avoid overlapping with other large backups or imports.<br />
<br />
For this first test, select Local Disk in Backup to and set Retain the latest to 3. This is a number of copies, not a guaranteed number of days. Extra manual executions can also consume retained copies. Use a retention count that covers your recovery needs and fits your storage capacity.<br />
<br />
<!-- start: postbit_attachments_attachment -->
<br /><!-- start: attachment_icon -->
<img src="https://adminsforum.com/images/attachtypes/image.png" title="JPG Image" border="0" alt=".jpg" />
<!-- end: attachment_icon -->&nbsp;&nbsp;<a href="attachment.php?aid=33" target="_blank" title="">cron-site-settings-20261012.jpg</a> (Size: 178.69 KB / Downloads: 9)
<!-- end: postbit_attachments_attachment --><br />
<span style="font-style: italic;" class="mycode_i">AdminsForum lab: the website backup settings before creating the task.</span><br />
<br />
If you later configure a remote storage integration, verify that a complete archive actually reaches that destination. Selecting a destination is not proof that its credentials, permissions or connectivity work.<br />
<br />
<span style="font-weight: bold;" class="mycode_b">4. Review exclusions carefully</span><br />
The Exclusion rules field can omit unwanted paths. We left it blank for the first test so the website document root was covered. Excluding uploads or a configuration file without a separate backup can prevent a complete recovery. Do not place your backup destination inside the site and then accidentally include old backups in every new archive.<br />
<br />
The Backup reminder field was left at non-receipt in our test. No failure notification was configured or tested. Configure and test notifications separately if you depend on them.<br />
<br />
<span style="font-weight: bold;" class="mycode_b">5. Create and run the task</span><br />
Click Add Task. Check the new row's site name, status, execution time, copy count and destination. It should show Running when enabled for future executions.<br />
<br />
In that row, click Execute and confirm the prompt. Wait for the run to finish. Use Log or Refresh log to read the outcome. A task row or last-execution timestamp alone does not prove that the backup succeeded.<br />
<br />
<!-- start: postbit_attachments_attachment -->
<br /><!-- start: attachment_icon -->
<img src="https://adminsforum.com/images/attachtypes/image.png" title="JPG Image" border="0" alt=".jpg" />
<!-- end: attachment_icon -->&nbsp;&nbsp;<a href="attachment.php?aid=34" target="_blank" title="">cron-site-log-20261012.jpg</a> (Size: 232.92 KB / Downloads: 8)
<!-- end: postbit_attachments_attachment --><br />
<span style="font-style: italic;" class="mycode_i">AdminsForum lab: successful first backup, including the archive path, size and retention setting.</span><br />
<br />
Our completed archive was saved under:<br />
<div class="codeblock"><div class="title af-code-title"><span>Code:</span><button type="button" class="af-code-copy" aria-label="Copy code" title="Copy code"><i class="far fa-copy" aria-hidden="true"></i><span>Copy</span></button><span class="af-code-status" role="status" aria-live="polite"></span></div><div class="body" dir="ltr"><code>/www/backup/site/adminslab.com/</code></div></div>Use the exact filename shown in your own log rather than copying a timestamped name from a tutorial.<br />
<br />
<span style="font-weight: bold;" class="mycode_b">6. Verify the archive</span><br />
Check that the file exists and has a plausible size. A compressed archive is usually smaller than the source directory, so compare with the actual content rather than expecting matching sizes.<br />
<br />
If you use the terminal, this read-only check verifies that tar can read the archive listing:<br />
<div class="codeblock"><div class="title af-code-title"><span>Code:</span><button type="button" class="af-code-copy" aria-label="Copy code" title="Copy code"><i class="far fa-copy" aria-hidden="true"></i><span>Copy</span></button><span class="af-code-status" role="status" aria-live="polite"></span></div><div class="body" dir="ltr"><code>tar -tzf /path/to/your-backup.tar.gz &gt; /dev/null &amp;&amp; echo 'Archive readable'</code></div></div>Replace the path with the real archive path from your log. We ran this check successfully on the lab archive. It does not prove that the application's database is included or that the website will recover correctly.<br />
<br />
For stronger recovery assurance, test extraction and application recovery in an isolated directory or separate test site. Avoid overwriting a live website simply to test a backup. See the <a href="https://adminsforum.com/Thread-guide-back-up-and-restore-website-files-in-aapanel-free-edition" target="_blank" rel="noopener" class="mycode_url">website file backup and restore guide</a> for the separate restore workflow.<br />
<br />
<span style="font-weight: bold;" class="mycode_b">7. Keep a copy away from the server</span><br />
Transfer an archive to protected off-server storage and verify that it can be downloaded again. Treat it as sensitive: website configuration files can contain database credentials. Do not attach backup archives to a public forum post or place them at a public download URL.<br />
<br />
Pair the file backup with a database backup from a compatible point in time. A rapidly changing site may need coordinated backups or a brief maintenance window for consistency.<br />
<br />
<span style="font-weight: bold;" class="mycode_b">8. Check future runs</span><br />
After the next scheduled time, inspect Last execute time and Log. Confirm a new archive appeared and that retention behaves as expected. We tested the task manually; you should still verify its first unattended execution on your server.<br />
<br />
To pause a task, select its checkbox, choose Stop task in the list action menu, click Execute and confirm. Reload the list and verify Stopped. We used this explicit stop action for the lab task. We preserved it for reference instead of leaving an unnecessary tutorial schedule running.<br />
<br />
<span style="font-weight: bold;" class="mycode_b">Troubleshooting</span><ul class="mycode_list"><li><span style="font-weight: bold;" class="mycode_b">No archive:</span> read the task log, check the selected website and document root, and confirm free disk space and permissions.<br />
</li>
<li><span style="font-weight: bold;" class="mycode_b">Unexpectedly small backup:</span> review exclusions and the actual source directory. Verify archive contents before relying on it.<br />
</li>
<li><span style="font-weight: bold;" class="mycode_b">Missed scheduled run:</span> check task status, server clock, cron service and logs. A manual Execute success does not prove the scheduled trigger ran.<br />
</li>
<li><span style="font-weight: bold;" class="mycode_b">Storage fills up:</span> review retention, other backup jobs and whether archives are being copied into the source site. Preserve needed recovery copies before changing cleanup behavior.<br />
</li>
</ul>
<br />
<span style="font-weight: bold;" class="mycode_b">Completion checklist</span><ul class="mycode_list"><li>Correct website and document root selected.<br />
</li>
<li>Schedule checked against the server clock.<br />
</li>
<li>Destination, retention and exclusions reviewed.<br />
</li>
<li>First Execute run has a successful log and an archive.<br />
</li>
<li>Archive readability checked and off-server storage planned.<br />
</li>
<li>Database backup and an isolated recovery test included in the plan.<br />
</li>
<li>First unattended run checked afterward.<br />
</li>
</ul>
<br />
<span style="font-weight: bold;" class="mycode_b">Reference:</span> <a href="https://www.aapanel.com/docs/Function/Cron.html" target="_blank" rel="noopener" class="mycode_url">aaPanel official Cron documentation</a>.]]></description>
			<content:encoded><![CDATA[<span style="font-weight: bold;" class="mycode_b">Quick answer</span><br />
Open Cron, choose Backup Site, select the website, set a daily time and a backup destination, then click Add Task. Run the task once with Execute and check its Log before trusting the schedule. Website files and the database need separate backup coverage.<br />
<br />
<span style="font-weight: bold;" class="mycode_b">Tested on the AdminsForum lab</span><br />
We created Backup Site[adminslab.com] in aaPanel 8.0.6, scheduled it for 02:10 using the server's clock, selected Local Disk and retained three copies. We manually executed the new task. The log reported Successful and created a 45.78 MB archive from a 119.08 MB document root. The archive passed a tar readability check. We paused the tutorial-only schedule after testing; the archive was preserved. An overnight scheduled execution and a restore of this specific archive were not tested.<br />
<br />
<span style="font-weight: bold;" class="mycode_b">1. Decide what you need to protect</span><br />
For a WordPress or other database-driven website, keep both the document-root files and its database. Files include application code, uploads and configuration. Database content such as posts, settings and accounts is separate.<br />
<br />
Check the site you want to back up, its document-root path and the available disk space first. Keep backup archives outside the public document root. A same-server backup helps with accidental file changes but cannot protect you from losing the entire server.<br />
<br />
<span style="font-weight: bold;" class="mycode_b">2. Select Backup Site</span><br />
Click Cron in the left-hand menu. In the Add Task section, open Task type and choose Backup Site. Select your particular website in Backup site. The lab's task name changed automatically to Backup Site[adminslab.com]. Choose ALL only when you actually want every listed site included.<br />
<br />
<span style="font-weight: bold;" class="mycode_b">3. Set the schedule and retention</span><br />
Choose Daily in Execute cycle, then enter the hour and minute. Our example is 02:10. These fields use the server's clock; check its time zone before treating the value as your local time. Choose a quiet period and avoid overlapping with other large backups or imports.<br />
<br />
For this first test, select Local Disk in Backup to and set Retain the latest to 3. This is a number of copies, not a guaranteed number of days. Extra manual executions can also consume retained copies. Use a retention count that covers your recovery needs and fits your storage capacity.<br />
<br />
<!-- start: postbit_attachments_attachment -->
<br /><!-- start: attachment_icon -->
<img src="https://adminsforum.com/images/attachtypes/image.png" title="JPG Image" border="0" alt=".jpg" />
<!-- end: attachment_icon -->&nbsp;&nbsp;<a href="attachment.php?aid=33" target="_blank" title="">cron-site-settings-20261012.jpg</a> (Size: 178.69 KB / Downloads: 9)
<!-- end: postbit_attachments_attachment --><br />
<span style="font-style: italic;" class="mycode_i">AdminsForum lab: the website backup settings before creating the task.</span><br />
<br />
If you later configure a remote storage integration, verify that a complete archive actually reaches that destination. Selecting a destination is not proof that its credentials, permissions or connectivity work.<br />
<br />
<span style="font-weight: bold;" class="mycode_b">4. Review exclusions carefully</span><br />
The Exclusion rules field can omit unwanted paths. We left it blank for the first test so the website document root was covered. Excluding uploads or a configuration file without a separate backup can prevent a complete recovery. Do not place your backup destination inside the site and then accidentally include old backups in every new archive.<br />
<br />
The Backup reminder field was left at non-receipt in our test. No failure notification was configured or tested. Configure and test notifications separately if you depend on them.<br />
<br />
<span style="font-weight: bold;" class="mycode_b">5. Create and run the task</span><br />
Click Add Task. Check the new row's site name, status, execution time, copy count and destination. It should show Running when enabled for future executions.<br />
<br />
In that row, click Execute and confirm the prompt. Wait for the run to finish. Use Log or Refresh log to read the outcome. A task row or last-execution timestamp alone does not prove that the backup succeeded.<br />
<br />
<!-- start: postbit_attachments_attachment -->
<br /><!-- start: attachment_icon -->
<img src="https://adminsforum.com/images/attachtypes/image.png" title="JPG Image" border="0" alt=".jpg" />
<!-- end: attachment_icon -->&nbsp;&nbsp;<a href="attachment.php?aid=34" target="_blank" title="">cron-site-log-20261012.jpg</a> (Size: 232.92 KB / Downloads: 8)
<!-- end: postbit_attachments_attachment --><br />
<span style="font-style: italic;" class="mycode_i">AdminsForum lab: successful first backup, including the archive path, size and retention setting.</span><br />
<br />
Our completed archive was saved under:<br />
<div class="codeblock"><div class="title af-code-title"><span>Code:</span><button type="button" class="af-code-copy" aria-label="Copy code" title="Copy code"><i class="far fa-copy" aria-hidden="true"></i><span>Copy</span></button><span class="af-code-status" role="status" aria-live="polite"></span></div><div class="body" dir="ltr"><code>/www/backup/site/adminslab.com/</code></div></div>Use the exact filename shown in your own log rather than copying a timestamped name from a tutorial.<br />
<br />
<span style="font-weight: bold;" class="mycode_b">6. Verify the archive</span><br />
Check that the file exists and has a plausible size. A compressed archive is usually smaller than the source directory, so compare with the actual content rather than expecting matching sizes.<br />
<br />
If you use the terminal, this read-only check verifies that tar can read the archive listing:<br />
<div class="codeblock"><div class="title af-code-title"><span>Code:</span><button type="button" class="af-code-copy" aria-label="Copy code" title="Copy code"><i class="far fa-copy" aria-hidden="true"></i><span>Copy</span></button><span class="af-code-status" role="status" aria-live="polite"></span></div><div class="body" dir="ltr"><code>tar -tzf /path/to/your-backup.tar.gz &gt; /dev/null &amp;&amp; echo 'Archive readable'</code></div></div>Replace the path with the real archive path from your log. We ran this check successfully on the lab archive. It does not prove that the application's database is included or that the website will recover correctly.<br />
<br />
For stronger recovery assurance, test extraction and application recovery in an isolated directory or separate test site. Avoid overwriting a live website simply to test a backup. See the <a href="https://adminsforum.com/Thread-guide-back-up-and-restore-website-files-in-aapanel-free-edition" target="_blank" rel="noopener" class="mycode_url">website file backup and restore guide</a> for the separate restore workflow.<br />
<br />
<span style="font-weight: bold;" class="mycode_b">7. Keep a copy away from the server</span><br />
Transfer an archive to protected off-server storage and verify that it can be downloaded again. Treat it as sensitive: website configuration files can contain database credentials. Do not attach backup archives to a public forum post or place them at a public download URL.<br />
<br />
Pair the file backup with a database backup from a compatible point in time. A rapidly changing site may need coordinated backups or a brief maintenance window for consistency.<br />
<br />
<span style="font-weight: bold;" class="mycode_b">8. Check future runs</span><br />
After the next scheduled time, inspect Last execute time and Log. Confirm a new archive appeared and that retention behaves as expected. We tested the task manually; you should still verify its first unattended execution on your server.<br />
<br />
To pause a task, select its checkbox, choose Stop task in the list action menu, click Execute and confirm. Reload the list and verify Stopped. We used this explicit stop action for the lab task. We preserved it for reference instead of leaving an unnecessary tutorial schedule running.<br />
<br />
<span style="font-weight: bold;" class="mycode_b">Troubleshooting</span><ul class="mycode_list"><li><span style="font-weight: bold;" class="mycode_b">No archive:</span> read the task log, check the selected website and document root, and confirm free disk space and permissions.<br />
</li>
<li><span style="font-weight: bold;" class="mycode_b">Unexpectedly small backup:</span> review exclusions and the actual source directory. Verify archive contents before relying on it.<br />
</li>
<li><span style="font-weight: bold;" class="mycode_b">Missed scheduled run:</span> check task status, server clock, cron service and logs. A manual Execute success does not prove the scheduled trigger ran.<br />
</li>
<li><span style="font-weight: bold;" class="mycode_b">Storage fills up:</span> review retention, other backup jobs and whether archives are being copied into the source site. Preserve needed recovery copies before changing cleanup behavior.<br />
</li>
</ul>
<br />
<span style="font-weight: bold;" class="mycode_b">Completion checklist</span><ul class="mycode_list"><li>Correct website and document root selected.<br />
</li>
<li>Schedule checked against the server clock.<br />
</li>
<li>Destination, retention and exclusions reviewed.<br />
</li>
<li>First Execute run has a successful log and an archive.<br />
</li>
<li>Archive readability checked and off-server storage planned.<br />
</li>
<li>Database backup and an isolated recovery test included in the plan.<br />
</li>
<li>First unattended run checked afterward.<br />
</li>
</ul>
<br />
<span style="font-weight: bold;" class="mycode_b">Reference:</span> <a href="https://www.aapanel.com/docs/Function/Cron.html" target="_blank" rel="noopener" class="mycode_url">aaPanel official Cron documentation</a>.]]></content:encoded>
		</item>
		<item>
			<title><![CDATA[Back Up and Restore Website Files in aaPanel Free Edition]]></title>
			<link>https://adminsforum.com/Thread-guide-back-up-and-restore-website-files-in-aapanel-free-edition</link>
			<pubDate>Sun, 11 Oct 2026 03:11:29 +0800</pubDate>
			<dc:creator><![CDATA[<a href="https://adminsforum.com/member.php?action=profile&uid=2">DEV</a>]]></dc:creator>
			<guid isPermaLink="false">https://adminsforum.com/Thread-guide-back-up-and-restore-website-files-in-aapanel-free-edition</guid>
			<description><![CDATA[<span style="font-weight: bold;" class="mycode_b">Quick answer</span><br />
In aaPanel Free Edition, open Website → PHP Project, find your domain, and click its Backup / Restore entry. Check the configured backup type, click Backup, and wait for completion. Keep an off-server copy and test recovery on a disposable site.<br />
<br />
<span style="font-weight: bold;" class="mycode_b">Website files and database are separate</span><br />
Our lab's backup configuration was <span style="font-weight: bold;" class="mycode_b">Only Site File → Local Server</span>. This backs up site files, not the application's database. Pair it with a <a href="https://adminsforum.com/Thread-guide-back-up-and-restore-a-database-in-aapanel-free-edition" target="_blank" rel="noopener" class="mycode_url">database backup</a>. Do not assume every backup labelled Website contains both.<br />
<br />
<span style="font-weight: bold;" class="mycode_b">1. Open the website backup dialog</span><br />
Go to <span style="font-weight: bold;" class="mycode_b">Website → PHP Project</span>. Find the correct domain and check its description. Click the <span style="font-weight: bold;" class="mycode_b">Backup / Restore</span> entry; for a new site this can read <span style="font-weight: bold;" class="mycode_b">0 Backup</span>. Dismiss the optional first-use help wizard if it blocks the controls.<br />
<br />
<span style="font-weight: bold;" class="mycode_b">2. Check the backup configuration</span><br />
Read the <span style="font-weight: bold;" class="mycode_b">Current configuration</span> line before starting. In this tested guide it was <span style="font-weight: bold;" class="mycode_b">Only Site File</span> stored on <span style="font-weight: bold;" class="mycode_b">Local Server</span>. Other configurations may behave differently. Record what is included and where it is stored. Ensure enough free disk space for the backup and restoration.<br />
<br />
<span style="font-weight: bold;" class="mycode_b">3. Create the backup</span><br />
Click <span style="font-weight: bold;" class="mycode_b">Backup</span> and wait for the task to complete. Confirm the archive appears with its file size, time, backup type and storage destination. Our small lab site produced a ZIP archive; actual sizes vary.<br />
<br />
<img src="https://adminsforum.com/attachment.php?aid=23" loading="lazy"  alt="[Image: attachment.php?aid=23]" class="mycode_img" /><br />
<span style="font-style: italic;" class="mycode_i">AdminsForum tutorial lab: aaPanel reports the website backup completed successfully.</span><br />
<br />
<span style="font-weight: bold;" class="mycode_b">4. Keep a copy outside the server</span><br />
Use the archive's <span style="font-weight: bold;" class="mycode_b">Download</span> action and confirm the transfer completed. Keep the file securely off the VPS. Website archives may contain configuration secrets and private uploads; never post a production archive publicly. A local backup will not protect against losing the entire server.<br />
<br />
<span style="font-weight: bold;" class="mycode_b">5. Test restoration on a disposable site</span><br />
For a real application, restore into an isolated test setup before trusting the backup. In our dedicated lab we created a harmless text file containing a known value, made the backup, changed that file, and restored the archive.<br />
<br />
<ol type="1" class="mycode_list"><li>Open the correct site's Backup / Restore dialog.<br />
</li>
<li>Identify the intended archive and its date.<br />
</li>
<li>Click <span style="font-weight: bold;" class="mycode_b">Restore</span>.<br />
</li>
<li>Read the confirmation carefully. Our panel displayed <span style="font-weight: bold;" class="mycode_b">Will be restoring the site files and database, continue?</span>, even though the archive type was Only Site File. Check the actual backup type rather than inferring its contents from this generic warning.<br />
</li>
<li>Confirm only after protecting current data and planning downtime.<br />
</li>
<li>Wait for the recovery task to finish and inspect its log.<br />
</li>
<li>Verify the recovered files, ownership/permissions, HTTPS site and application behavior.<br />
</li>
</ol>
<br />
<span style="font-weight: bold;" class="mycode_b">Restore can replace current files and interrupt service.</span> In our test the website briefly returned HTTP 403 while its directory was being restored, then returned HTTP 200 after completion. Plan a maintenance window for a live site and do not treat the temporary state as a completed restore.<br />
<br />
<span style="font-weight: bold;" class="mycode_b">6. Check the result</span><br />
Verify a known file or upload, the homepage, application login and important functions. Restore the corresponding database when needed, using a consistent recovery point. Website files alone do not restore a database-backed application fully.<br />
<br />
<span style="font-weight: bold;" class="mycode_b">What we tested</span><br />
On 10 October 2026, aaPanel Free Edition 8.0.6 created an Only Site File backup for our dedicated lab domain. We copied the archive to a separate computer, changed a disposable test file and restored through the panel. Both a filesystem check and an HTTPS request confirmed the original text returned. The homepage returned HTTP 200 after recovery.<br />
<br />
<span style="font-weight: bold;" class="mycode_b">Common questions</span><br />
<span style="font-weight: bold;" class="mycode_b">Is this a VPS snapshot?</span><br />
No. This backup does not capture the whole operating system or all server settings.<br />
<br />
<span style="font-weight: bold;" class="mycode_b">Does this set up scheduled backups?</span><br />
No. The dialog has a separate Schedule &amp; Remote Storage section. A reliable schedule also needs retention, off-server storage, monitoring and restore testing.<br />
<br />
<span style="font-weight: bold;" class="mycode_b">Should I leave backup archives in the website root?</span><br />
No. Keep backups outside publicly served folders and protect them appropriately.<br />
<br />
<span style="font-weight: bold;" class="mycode_b">What if the application still fails after files are recovered?</span><br />
Check the database recovery point, PHP version and extensions, environment settings, file permissions and logs. File recovery alone may not undo application/database changes.<br />
<br />
<span style="font-weight: bold;" class="mycode_b">Related guides</span><br />
<a href="https://adminsforum.com/Thread-guide-back-up-and-restore-a-database-in-aapanel-free-edition" target="_blank" rel="noopener" class="mycode_url">Back up and restore a database in aaPanel Free Edition</a><br />
<a href="https://adminsforum.com/Thread-guide-change-php-8-3-to-8-5-in-aapanel-free-edition" target="_blank" rel="noopener" class="mycode_url">Change PHP 8.3 to 8.5 in aaPanel Free Edition</a><br /><!-- start: postbit_attachments_attachment -->
<br /><!-- start: attachment_icon -->
<img src="https://adminsforum.com/images/attachtypes/image.png" title="JPG Image" border="0" alt=".jpg" />
<!-- end: attachment_icon -->&nbsp;&nbsp;<a href="attachment.php?aid=23" target="_blank" title="">website-backup-success-safe-20261010.jpg</a> (Size: 11.5 KB / Downloads: 8)
<!-- end: postbit_attachments_attachment -->]]></description>
			<content:encoded><![CDATA[<span style="font-weight: bold;" class="mycode_b">Quick answer</span><br />
In aaPanel Free Edition, open Website → PHP Project, find your domain, and click its Backup / Restore entry. Check the configured backup type, click Backup, and wait for completion. Keep an off-server copy and test recovery on a disposable site.<br />
<br />
<span style="font-weight: bold;" class="mycode_b">Website files and database are separate</span><br />
Our lab's backup configuration was <span style="font-weight: bold;" class="mycode_b">Only Site File → Local Server</span>. This backs up site files, not the application's database. Pair it with a <a href="https://adminsforum.com/Thread-guide-back-up-and-restore-a-database-in-aapanel-free-edition" target="_blank" rel="noopener" class="mycode_url">database backup</a>. Do not assume every backup labelled Website contains both.<br />
<br />
<span style="font-weight: bold;" class="mycode_b">1. Open the website backup dialog</span><br />
Go to <span style="font-weight: bold;" class="mycode_b">Website → PHP Project</span>. Find the correct domain and check its description. Click the <span style="font-weight: bold;" class="mycode_b">Backup / Restore</span> entry; for a new site this can read <span style="font-weight: bold;" class="mycode_b">0 Backup</span>. Dismiss the optional first-use help wizard if it blocks the controls.<br />
<br />
<span style="font-weight: bold;" class="mycode_b">2. Check the backup configuration</span><br />
Read the <span style="font-weight: bold;" class="mycode_b">Current configuration</span> line before starting. In this tested guide it was <span style="font-weight: bold;" class="mycode_b">Only Site File</span> stored on <span style="font-weight: bold;" class="mycode_b">Local Server</span>. Other configurations may behave differently. Record what is included and where it is stored. Ensure enough free disk space for the backup and restoration.<br />
<br />
<span style="font-weight: bold;" class="mycode_b">3. Create the backup</span><br />
Click <span style="font-weight: bold;" class="mycode_b">Backup</span> and wait for the task to complete. Confirm the archive appears with its file size, time, backup type and storage destination. Our small lab site produced a ZIP archive; actual sizes vary.<br />
<br />
<img src="https://adminsforum.com/attachment.php?aid=23" loading="lazy"  alt="[Image: attachment.php?aid=23]" class="mycode_img" /><br />
<span style="font-style: italic;" class="mycode_i">AdminsForum tutorial lab: aaPanel reports the website backup completed successfully.</span><br />
<br />
<span style="font-weight: bold;" class="mycode_b">4. Keep a copy outside the server</span><br />
Use the archive's <span style="font-weight: bold;" class="mycode_b">Download</span> action and confirm the transfer completed. Keep the file securely off the VPS. Website archives may contain configuration secrets and private uploads; never post a production archive publicly. A local backup will not protect against losing the entire server.<br />
<br />
<span style="font-weight: bold;" class="mycode_b">5. Test restoration on a disposable site</span><br />
For a real application, restore into an isolated test setup before trusting the backup. In our dedicated lab we created a harmless text file containing a known value, made the backup, changed that file, and restored the archive.<br />
<br />
<ol type="1" class="mycode_list"><li>Open the correct site's Backup / Restore dialog.<br />
</li>
<li>Identify the intended archive and its date.<br />
</li>
<li>Click <span style="font-weight: bold;" class="mycode_b">Restore</span>.<br />
</li>
<li>Read the confirmation carefully. Our panel displayed <span style="font-weight: bold;" class="mycode_b">Will be restoring the site files and database, continue?</span>, even though the archive type was Only Site File. Check the actual backup type rather than inferring its contents from this generic warning.<br />
</li>
<li>Confirm only after protecting current data and planning downtime.<br />
</li>
<li>Wait for the recovery task to finish and inspect its log.<br />
</li>
<li>Verify the recovered files, ownership/permissions, HTTPS site and application behavior.<br />
</li>
</ol>
<br />
<span style="font-weight: bold;" class="mycode_b">Restore can replace current files and interrupt service.</span> In our test the website briefly returned HTTP 403 while its directory was being restored, then returned HTTP 200 after completion. Plan a maintenance window for a live site and do not treat the temporary state as a completed restore.<br />
<br />
<span style="font-weight: bold;" class="mycode_b">6. Check the result</span><br />
Verify a known file or upload, the homepage, application login and important functions. Restore the corresponding database when needed, using a consistent recovery point. Website files alone do not restore a database-backed application fully.<br />
<br />
<span style="font-weight: bold;" class="mycode_b">What we tested</span><br />
On 10 October 2026, aaPanel Free Edition 8.0.6 created an Only Site File backup for our dedicated lab domain. We copied the archive to a separate computer, changed a disposable test file and restored through the panel. Both a filesystem check and an HTTPS request confirmed the original text returned. The homepage returned HTTP 200 after recovery.<br />
<br />
<span style="font-weight: bold;" class="mycode_b">Common questions</span><br />
<span style="font-weight: bold;" class="mycode_b">Is this a VPS snapshot?</span><br />
No. This backup does not capture the whole operating system or all server settings.<br />
<br />
<span style="font-weight: bold;" class="mycode_b">Does this set up scheduled backups?</span><br />
No. The dialog has a separate Schedule &amp; Remote Storage section. A reliable schedule also needs retention, off-server storage, monitoring and restore testing.<br />
<br />
<span style="font-weight: bold;" class="mycode_b">Should I leave backup archives in the website root?</span><br />
No. Keep backups outside publicly served folders and protect them appropriately.<br />
<br />
<span style="font-weight: bold;" class="mycode_b">What if the application still fails after files are recovered?</span><br />
Check the database recovery point, PHP version and extensions, environment settings, file permissions and logs. File recovery alone may not undo application/database changes.<br />
<br />
<span style="font-weight: bold;" class="mycode_b">Related guides</span><br />
<a href="https://adminsforum.com/Thread-guide-back-up-and-restore-a-database-in-aapanel-free-edition" target="_blank" rel="noopener" class="mycode_url">Back up and restore a database in aaPanel Free Edition</a><br />
<a href="https://adminsforum.com/Thread-guide-change-php-8-3-to-8-5-in-aapanel-free-edition" target="_blank" rel="noopener" class="mycode_url">Change PHP 8.3 to 8.5 in aaPanel Free Edition</a><br /><!-- start: postbit_attachments_attachment -->
<br /><!-- start: attachment_icon -->
<img src="https://adminsforum.com/images/attachtypes/image.png" title="JPG Image" border="0" alt=".jpg" />
<!-- end: attachment_icon -->&nbsp;&nbsp;<a href="attachment.php?aid=23" target="_blank" title="">website-backup-success-safe-20261010.jpg</a> (Size: 11.5 KB / Downloads: 8)
<!-- end: postbit_attachments_attachment -->]]></content:encoded>
		</item>
		<item>
			<title><![CDATA[Back Up and Restore a Database in aaPanel Free Edition]]></title>
			<link>https://adminsforum.com/Thread-guide-back-up-and-restore-a-database-in-aapanel-free-edition</link>
			<pubDate>Sun, 11 Oct 2026 03:07:18 +0800</pubDate>
			<dc:creator><![CDATA[<a href="https://adminsforum.com/member.php?action=profile&uid=2">DEV</a>]]></dc:creator>
			<guid isPermaLink="false">https://adminsforum.com/Thread-guide-back-up-and-restore-a-database-in-aapanel-free-edition</guid>
			<description><![CDATA[<span style="font-weight: bold;" class="mycode_b">Quick answer</span><br />
In aaPanel Free Edition, open Databases, find your MySQL/MariaDB database, and click its Backup column. Click Backup, wait for the archive to appear, then use Download to keep a copy off the VPS. Test recovery before relying on a backup.<br />
<br />
<span style="font-weight: bold;" class="mycode_b">1. Choose the correct database</span><br />
Open <span style="font-weight: bold;" class="mycode_b">Databases → MySQL</span>. Match the database name with your application's configuration. Do not expose passwords or production dumps in screenshots or public posts. When no backup exists, click <span style="font-weight: bold;" class="mycode_b">Not exist</span> in the Backup column. Otherwise click the existing backup entry to open Database Backup Details.<br />
<br />
<span style="font-weight: bold;" class="mycode_b">2. Create a manual backup</span><br />
Click <span style="font-weight: bold;" class="mycode_b">Backup</span> and wait for completion. Confirm a new archive appears with a filename, file size, backup time and storage type. Our aaPanel Free Edition 8.0.6 lab created a .sql.zip archive on local disk.<br />
<br />
<img src="https://adminsforum.com/attachment.php?aid=22" loading="lazy"  alt="[Image: attachment.php?aid=22]" class="mycode_img" /><br />
<span style="font-style: italic;" class="mycode_i">AdminsForum tutorial lab: completed backup controls. Database names and internal paths are excluded from this image.</span><br />
<br />
File size depends on database contents. Our tiny tutorial database is not representative of a production database. The backup time follows the server/panel timezone.<br />
<br />
<span style="font-weight: bold;" class="mycode_b">3. Download an off-server copy</span><br />
Click <span style="font-weight: bold;" class="mycode_b">Download</span> beside the archive and confirm the download completed. Store it securely outside this VPS. A local backup can be lost with the server. Database archives may contain user data and password hashes; never post a production archive publicly.<br />
<br />
<span style="font-weight: bold;" class="mycode_b">4. Test recovery safely</span><br />
For a real website, restore into a separate test database and test a staging copy of the application. Do not practice on a live database. In our disposable lab, we backed up a known tutorial row, changed it, and recovered the archive to check whether the original value returned.<br />
<br />
<ol type="1" class="mycode_list"><li>Open the intended database's backup details.<br />
</li>
<li>Identify the correct archive by database name and backup time.<br />
</li>
<li>Click <span style="font-weight: bold;" class="mycode_b">Recover</span>.<br />
</li>
<li>Read the warning: <span style="font-weight: bold;" class="mycode_b">Database will be overwritten, continue?</span><br />
</li>
<li>Confirm only after verifying the target and protecting any newer data you need to retain.<br />
</li>
<li>Wait for import completion, review its result/log and check the restored tables and records.<br />
</li>
</ol>
<br />
<span style="font-weight: bold;" class="mycode_b">Recover can overwrite existing data.</span> Before restoring a live database, take a current backup and plan for downtime or paused application writes. Switching to an older backup can lose data created after that backup.<br />
<br />
<span style="font-weight: bold;" class="mycode_b">5. Verify restored data</span><br />
Check expected tables and a known record, then test relevant application operations such as login and pages that read the database. A ZIP download or successful import message alone is insufficient.<br />
<br />
<span style="font-weight: bold;" class="mycode_b">What we tested</span><br />
On 10 October 2026, we used aaPanel Free Edition 8.0.6 on Ubuntu 22.04 with MariaDB 10.11. We created a backup in the panel, downloaded the archive to another computer, changed a disposable tutorial row and used Recover. A database query confirmed the row returned to its original value, <span style="font-weight: bold;" class="mycode_b">AdminsForum backup tutorial</span>. Larger applications require their own recovery and consistency checks.<br />
<br />
<span style="font-weight: bold;" class="mycode_b">Common questions</span><br />
<span style="font-weight: bold;" class="mycode_b">Does this include website files?</span><br />
No. Back up the website directory separately, and keep file/database recovery points consistent before an application upgrade.<br />
<br />
<span style="font-weight: bold;" class="mycode_b">Does this create scheduled backups?</span><br />
No. This is a manual backup. Automatic backups need a separate schedule, storage destination, retention policy and successful-run checks.<br />
<br />
<span style="font-weight: bold;" class="mycode_b">What if backup or import fails?</span><br />
Read the task log, check free disk space and database service status, and verify the selected archive. Do not repeatedly restore over live data without understanding the failure.<br />
<br />
<span style="font-weight: bold;" class="mycode_b">Can old backups be removed?</span><br />
Keep enough verified recovery points for your needs. Do not remove the only known-good backup while testing a replacement.<br />
<br />
<span style="font-weight: bold;" class="mycode_b">Related guides</span><br />
<a href="https://adminsforum.com/Thread-guide-create-a-database-and-user-in-aapanel-free-edition" target="_blank" rel="noopener" class="mycode_url">Create a database and user in aaPanel Free Edition</a><br />
<a href="https://adminsforum.com/Thread-guide-change-php-8-3-to-8-5-in-aapanel-free-edition" target="_blank" rel="noopener" class="mycode_url">Change PHP 8.3 to 8.5 in aaPanel Free Edition</a><br /><!-- start: postbit_attachments_attachment -->
<br /><!-- start: attachment_icon -->
<img src="https://adminsforum.com/images/attachtypes/image.png" title="JPG Image" border="0" alt=".jpg" />
<!-- end: attachment_icon -->&nbsp;&nbsp;<a href="attachment.php?aid=22" target="_blank" title="">database-backup-controls-safe-20261010.jpg</a> (Size: 9.59 KB / Downloads: 5)
<!-- end: postbit_attachments_attachment -->]]></description>
			<content:encoded><![CDATA[<span style="font-weight: bold;" class="mycode_b">Quick answer</span><br />
In aaPanel Free Edition, open Databases, find your MySQL/MariaDB database, and click its Backup column. Click Backup, wait for the archive to appear, then use Download to keep a copy off the VPS. Test recovery before relying on a backup.<br />
<br />
<span style="font-weight: bold;" class="mycode_b">1. Choose the correct database</span><br />
Open <span style="font-weight: bold;" class="mycode_b">Databases → MySQL</span>. Match the database name with your application's configuration. Do not expose passwords or production dumps in screenshots or public posts. When no backup exists, click <span style="font-weight: bold;" class="mycode_b">Not exist</span> in the Backup column. Otherwise click the existing backup entry to open Database Backup Details.<br />
<br />
<span style="font-weight: bold;" class="mycode_b">2. Create a manual backup</span><br />
Click <span style="font-weight: bold;" class="mycode_b">Backup</span> and wait for completion. Confirm a new archive appears with a filename, file size, backup time and storage type. Our aaPanel Free Edition 8.0.6 lab created a .sql.zip archive on local disk.<br />
<br />
<img src="https://adminsforum.com/attachment.php?aid=22" loading="lazy"  alt="[Image: attachment.php?aid=22]" class="mycode_img" /><br />
<span style="font-style: italic;" class="mycode_i">AdminsForum tutorial lab: completed backup controls. Database names and internal paths are excluded from this image.</span><br />
<br />
File size depends on database contents. Our tiny tutorial database is not representative of a production database. The backup time follows the server/panel timezone.<br />
<br />
<span style="font-weight: bold;" class="mycode_b">3. Download an off-server copy</span><br />
Click <span style="font-weight: bold;" class="mycode_b">Download</span> beside the archive and confirm the download completed. Store it securely outside this VPS. A local backup can be lost with the server. Database archives may contain user data and password hashes; never post a production archive publicly.<br />
<br />
<span style="font-weight: bold;" class="mycode_b">4. Test recovery safely</span><br />
For a real website, restore into a separate test database and test a staging copy of the application. Do not practice on a live database. In our disposable lab, we backed up a known tutorial row, changed it, and recovered the archive to check whether the original value returned.<br />
<br />
<ol type="1" class="mycode_list"><li>Open the intended database's backup details.<br />
</li>
<li>Identify the correct archive by database name and backup time.<br />
</li>
<li>Click <span style="font-weight: bold;" class="mycode_b">Recover</span>.<br />
</li>
<li>Read the warning: <span style="font-weight: bold;" class="mycode_b">Database will be overwritten, continue?</span><br />
</li>
<li>Confirm only after verifying the target and protecting any newer data you need to retain.<br />
</li>
<li>Wait for import completion, review its result/log and check the restored tables and records.<br />
</li>
</ol>
<br />
<span style="font-weight: bold;" class="mycode_b">Recover can overwrite existing data.</span> Before restoring a live database, take a current backup and plan for downtime or paused application writes. Switching to an older backup can lose data created after that backup.<br />
<br />
<span style="font-weight: bold;" class="mycode_b">5. Verify restored data</span><br />
Check expected tables and a known record, then test relevant application operations such as login and pages that read the database. A ZIP download or successful import message alone is insufficient.<br />
<br />
<span style="font-weight: bold;" class="mycode_b">What we tested</span><br />
On 10 October 2026, we used aaPanel Free Edition 8.0.6 on Ubuntu 22.04 with MariaDB 10.11. We created a backup in the panel, downloaded the archive to another computer, changed a disposable tutorial row and used Recover. A database query confirmed the row returned to its original value, <span style="font-weight: bold;" class="mycode_b">AdminsForum backup tutorial</span>. Larger applications require their own recovery and consistency checks.<br />
<br />
<span style="font-weight: bold;" class="mycode_b">Common questions</span><br />
<span style="font-weight: bold;" class="mycode_b">Does this include website files?</span><br />
No. Back up the website directory separately, and keep file/database recovery points consistent before an application upgrade.<br />
<br />
<span style="font-weight: bold;" class="mycode_b">Does this create scheduled backups?</span><br />
No. This is a manual backup. Automatic backups need a separate schedule, storage destination, retention policy and successful-run checks.<br />
<br />
<span style="font-weight: bold;" class="mycode_b">What if backup or import fails?</span><br />
Read the task log, check free disk space and database service status, and verify the selected archive. Do not repeatedly restore over live data without understanding the failure.<br />
<br />
<span style="font-weight: bold;" class="mycode_b">Can old backups be removed?</span><br />
Keep enough verified recovery points for your needs. Do not remove the only known-good backup while testing a replacement.<br />
<br />
<span style="font-weight: bold;" class="mycode_b">Related guides</span><br />
<a href="https://adminsforum.com/Thread-guide-create-a-database-and-user-in-aapanel-free-edition" target="_blank" rel="noopener" class="mycode_url">Create a database and user in aaPanel Free Edition</a><br />
<a href="https://adminsforum.com/Thread-guide-change-php-8-3-to-8-5-in-aapanel-free-edition" target="_blank" rel="noopener" class="mycode_url">Change PHP 8.3 to 8.5 in aaPanel Free Edition</a><br /><!-- start: postbit_attachments_attachment -->
<br /><!-- start: attachment_icon -->
<img src="https://adminsforum.com/images/attachtypes/image.png" title="JPG Image" border="0" alt=".jpg" />
<!-- end: attachment_icon -->&nbsp;&nbsp;<a href="attachment.php?aid=22" target="_blank" title="">database-backup-controls-safe-20261010.jpg</a> (Size: 9.59 KB / Downloads: 5)
<!-- end: postbit_attachments_attachment -->]]></content:encoded>
		</item>
	</channel>
</rss>