A XenForo backup is not a zip of admin.php. It is the database and the two directories that hold everything members uploaded, and a way to put those three things back onto a board that is the same version you took them from. Miss data/ and avatars vanish. Miss internal_data/install-lock.php and the installer thinks you want a fresh site. Miss the version match and you are not restoring — you are inventing an upgrade you did not plan.
This is not the 2.3 upgrade decision. That article already walked Tools → Upgrade check, the upgrade-only package, and why you cannot downgrade. This is the operational loop around that click: backup, restore, clone a host, move a host, and the official importer as an overview. A phpBB 3.2–3.3 deep-dive is a later article. Do not treat this page as that walkthrough.
Official sources: the upgrade manual (docs.xenforo.com/manual/upgrade), the importing overview, configuration, and run pages (/manual/importing/…). Community operations fill host-move order and the Board URL / cookie-path trap the mistakes article already named.
Three jobs people mix up
Say “migration” and three different tickets arrive. Do the one you mean.
| Job | What moves | What must match | Success looks like |
|---|---|---|---|
| Backup / restore | Database + files, same box or a disaster box | Same XenForo version on the files you drop the dump into | Members, avatars, attachments, ACP add-ons, all back |
| Clone / move host | Same as restore, then config | Same version, then Board URL and cookie path | Login survives a refresh on the new hostname |
| Import | Users, forums, threads, posts, PMs from another product (or another XF) | Importer add-on; source never modified | New XF content; old URLs need redirect scripts |
An upgrade is a fourth job. Official: backup first; it is not possible to downgrade once you start the upgrade. The only reverse is the restore in the first row. If you do not have that restore, you do not have an upgrade window.
What you are actually copying
XenForo’s public tree is PHP in the web root. The member-generated board is not.
| Piece | Where it lives | If you omit it |
|---|---|---|
| Database | MySQL / MariaDB (official 2.3 floor: MySQL 5.7; 8.0 or MariaDB recommended) | Empty forum. Users, posts, permissions, styles-as-data, all gone |
data/ |
Web root (avatars, attachments, and other public data files) | Official upgrade manual: attachments and avatars may have been removed |
internal_data/ |
Web root (code cache, add-on files XenForo wrote, install-lock.php, other private data) |
Installer offers a fresh install. Attachments/avatars also live here depending on config |
src/config.php |
Not in the upgrade package | Board cannot find the database. Debug and cache flags live here |
PHP files (admin.php, src/, add-on directories) |
Web root | Version mismatch or missing add-ons |
Official common-upgrading-problems page, the sentence people skip: if after uploading files you are taken to perform a fresh install, files were not merged correctly and it is possible files were removed unexpectedly. At a minimum, create internal_data/install-lock.php. The contents do not matter. Then open /install/ again. If it still offers a fresh install, contact support — do not click through.
Same page: if internal_data or data are missing or empty, restore them from a backup. There is no ACP button that rebuilds years of avatars.
src/config.php is never in the Customer Area zip. Treat it as a secret. Copy it with the backup. Do not commit it. After a move, you will edit Board URL in the ACP and cookie path in this file — the mistakes article is the autopsy of getting those two wrong.
Close the board first
Official importer run page: it is also a good idea to close your forums (using the Board active option) for the duration of the import. The same switch is the right one for a restore, a host move, and any backup you want to be internally consistent.
Setup → Options → Board active (wording on the Basic board / board-active control — use the option XenForo ships named Board active). When it is off, visitors see the offline page. Staff with ACP access can still work. A backup taken while members are mid-post can still be restored; it is just a backup of a moving target. For a planned move, close, wait a minute for cron and last writes, then dump.
Do not confuse Board active with deleting cron. Tools → Cron entries should still exist. You are closing the front door, not disabling the building.
Backup: database, then the two directories, then the rest
There is no official “Backup now” button that writes a complete disaster archive. Official language is “backup your XenForo database and files.” You do that with the host’s tools.
1. Database
Dump the schema and data for the database named in src/config.php. Typical CLI shape (names are yours):
mysqldump --single-transaction --routines --triggers -u USER -p DBNAME > xf-$(date +%F).sql
--single-transaction is the InnoDB-friendly consistent read. Official 2.3 materials assume InnoDB for almost everything; community leftovers on MyISAM include xf_search_index and some session tables. If your host only offers a phpMyAdmin export, use custom, SQL, and include routines. Do not use a “quick” export that skips the search index and then wonder why search is empty — you can rebuild search. You cannot rebuild posts.
Store the dump off the web root. A .sql under /data/ is a public leak if the server ever serves that path.
2. data/ and internal_data/
Archive both directories as they stand. They can be large. They are the reason a 200 MB database restore still looks like a new board.
tar -czf xf-data-$(date +%F).tar.gz data internal_data
Permissions matter on restore. Those directories must be writable by the PHP user. Official install docs cover this on first install; a move to a new host often arrives with data/ owned by root from your laptop unzip. Symptom: avatars 500, attachments 500, ACP “cannot write.” Fix ownership. Do not chmod 777 the tree and leave it.
3. Application files
Copy the rest of the web root, or at least src/ (including config.php), add-on directories under src/addons/, and any child-style files you maintain outside the database. The database holds compiled style data; your laptop holds the extra.less you will want six months later.
If the goal is “I can rebuild this box from nothing,” also write down: PHP version, MySQL version, every add-on, the parent style, whether Redis is on. The 2.3 upgrade inventory is the same list. If you cannot write it, you do not have a backup procedure. You have a folder of files.
4. Prove the backup
A file that has never been restored is a rumour. Restore the dump onto a staging database, point a clone’s config.php at it, copy data/ and internal_data/, open the board. Look at one old avatar, one old attachment, one staff account, Tools → Cron entries. If that fails, the production backup you just took is also a rumour.
Restore: same version, then URL, then cookies
Official rule, operationally: the files and the database must be the same XenForo version. A 2.3.6 dump dropped onto 2.3.10 files is an accidental upgrade. A 2.3.10 dump dropped onto 2.2 files is a crash. A 2.3 dump dropped onto an empty directory of 2.3 files without install-lock.php is a fresh-install wizard.
Order that works:
- Put same-version XenForo files in the new root (from your file backup, not a random Customer Area full package of a newer build).
- Restore
data/andinternal_data/over those files. Confirminternal_data/install-lock.phpexists. Contents do not matter if you must recreate it, but prefer the real file from backup. - Restore
src/config.phpfrom backup. Point it at the new database credentials if the host changed. - Import the SQL dump into that database.
- Confirm PHP can write
data/andinternal_data/. - Open
/install/only if the board says it needs to. On a clean same-version restore it should already be a live board. - Log into the ACP. Fix Board URL. Fix cookie path. Turn Board active on when you mean to.
Board URL and cookie path
This is the move that looks like “restore failed.” Official connected-accounts and options: Board URL is the canonical public URL. A $config['cookie']['path'] (or domain) that does not cover the XenForo root means cookies never stick. Everyone looks like a guest. You then enable guest page cache and “logged-in users see the guest homepage.” They were never logged in.
After every restore onto a new hostname or subdirectory:
- Setup → Options → Basic board information → Board URL —
https://new.exampleorhttps://new.example/community, one canonical, pick a trailing-slash policy and keep it. The mistakes article: slash vs no-slash breaks connected accounts and payment return URLs. src/config.phpcookiepath—/if the board is at the domain root;/community/if that is the XF root.- Cookie
domain— blank unless you know you need a parent domain for two hosts. A leftover.old-domain.comis a silent logout.
Then: guest window, Registered throwaway, staff. Login must survive a refresh. If it does not, stop. Do not install an add-on. Do not rebuild caches as a superstition. Fix the URL and the cookie.
Related official “never on live” after a sloppy clone: $config['debug'] = false and $config['development']['fullJs'] = false. Debug prints SQL to visitors. The mistakes article is the rest of that list.
Clone: empty-to-empty XenForo
A staging clone is a restore plus a new hostname. Official upgrade manual: if possible, perform a test upgrade on a test installation before production. That test installation is this section.
- Provision PHP / MySQL that match production (or the versions you intend to land on). Official 2.3 PHP floor is 7.2, 8.3 or 8.4 recommended.
- Create an empty database. Do not install a second XenForo with the installer if you already have a dump — the installer will write a new
install-lockand a new empty schema. Restore onto empty tables instead. - Copy files +
data/+internal_data/+ dump as above. - Change
config.phpdatabase name, user, password. Change cookie path if the clone lives in a subdirectory (staging.examplevsexample.com/xf/). - ACP → Board URL → the staging URL.
- Disable outbound mail or point it at a sink, or you will email real members from staging. Official Setup → Options → Email options is transport (PHP built-in mail, SMTP, Google OAuth). There is no official “staging mute” toggle in the pages cited here. Operational pattern: a transport that cannot leave the box, or a
config.phpmail override if you already use one. Do not invent a core switch the manual does not name. - Turn off payment profiles you do not want to charge. Board URL on staging will also break return URLs — that is a feature.
- Board active on for staff, or off if the clone is on a public hostname you have not locked down.
Guest page cache on a clone that still has production Board URL is how you debug the wrong site. Official cache: $config['pageCache']['enabled'] needs a dedicated $config['cache']['context']['page'] provider. Disable cache on the clone until the URL is right. The speed article owns the rest of cache. This one only needs: do not clone a half-enabled page cache and call the restore broken.
Move host: production to production
Same as clone, with DNS at the end.
- Close Board active on the old host.
- Final dump + final
data/+internal_data/archives. Timestamp them. - Restore on the new host using the same XenForo version.
- Set Board URL to the URL members will use after DNS (or to a temporary hostname if you will 301 later — pick one and do not flip twice).
- Prove login, avatars, one attachment, ACP, a test mail to yourself.
- Point DNS. Wait. Confirm the new box sees the traffic (host file test first if you can).
- Open Board active.
- Keep the old box read-only or offline until you have a day of clean logs. The old box is the rollback.
Do not “just copy public_html” and leave the old database in place with a remote config.php. Official importer notes on speed apply here too: every request over a network is latency. A live board whose MySQL is 40 ms away will feel cursed. Move the database with the files.
Friendly URLs after a move are a rewrite problem, not a XenForo problem. If /index.php?forums/ works and /forums/ 404s, the new host is missing mod_rewrite / AllowOverride (Apache: rename htaccess.txt → .htaccess), LiteSpeed equivalent, IIS web.config, or nginx try_files. Official SEO chapter names those. Protect internal_data, src, install/data, install/templates on nginx — the official /xf/ example, change the path. The later SEO article owns IndexNow and sitemaps. After a move, submit the sitemap again because the hostname changed.
Upgrade sits on top of backup
Official upgrade warning, twice, because it is the whole policy: before upgrading, backup your XenForo database and files. It is not possible to downgrade once you start the upgrade. XenForo 1 → 2 repeats it: the only method of downgrading will be to restore from a backup.
Two supported upgrade paths, already detailed in the 2.3 article:
- Tools → Upgrade check — one-click if the server can download. Keep the browser window open until complete.
- Manual: Customer Area → Download the upgrade package only → merge the contents of
upload/into the root (the directory that already hasadmin.phpandcss.php) →/install/.
Official upload note: merge, do not replace. Some FTP clients replace the server directory with exactly what you uploaded. That is how data/ and internal_data/ disappear. Official: if the upload directory itself is uploaded, /install/ reports no upgrade found because you are not overwriting existing files.
After upgrade: Appearance → Outdated templates and Outdated phrases. Merge immediately. Official: important or new functionality may be broken or missing if an outdated template remains unmanaged.
If one-click or /install/ offers a fresh install, you lost install-lock.php. Recreate the file, do not run the fresh wizard on a live database.
CLI: official manuals document php cmd.php xf:import for imports. They did not, in the pages cited here, quote an upgrade verb. On a real server, run php cmd.php and read the command list rather than pasting a blog’s xf:upgrade from memory. If you are not already operating the board from CLI, use /install/ in a browser.
Importer overview (not the phpBB article)
Official: XenForo has the ability to import users, forums, threads, posts, private messages, and other data from other software. Importers are a separate add-on you download from the Customer area. They are not in the default zip.
At the time of writing, official sources listed:
- XenForo 2.x
- vBulletin 3.6 to 5.3
- IPS 4.x
- phpBB 3.2 to 3.3
- SMF 2.0
- MyBB 1.8
- Discourse 3.x
phpBB 3.3 community reports exist (including 3.3.15 → XF 2.3.10). The step-by-step, retain-ID choices, and redirect scripts for phpBB are the later dedicated article. Here you only need the shape.
Before you start
Official run-page warning, verbatim in spirit: always perform a full backup of your XenForo database and the data and internal_data directories before running an import. The source database and source files are never modified. The safety net is the XenForo side, so you can throw the import away and start again.
Close Board active.
Fastest official path: back up source DB + files, perform the import on the fastest server available, with both databases and files local. Network latency on every query is “massive slow-down.” Then deploy the result.
Tools → Import data
ACP: Tools → Import data. Choose a source. Official note: at the time of writing all existing importers target XenForo itself; later there may be importers that target Media Gallery, Resource Manager, or third-party products.
Configuration: source database details. Some importers auto-fill from a leftover config file if XF is installed in the same location the source used to occupy.
Steps: each data type is a step. Dependencies exist (posts need threads need forums). Un-check what you want to skip (users without avatars, for example). Official: once the import has started, you cannot go back and change the steps. Select everything you want before you run.
Retain content IDs: only on a completely empty XenForo installation that has no threads and posts. It tries to keep source IDs (thread 2563 stays 2563). Default is sequential new IDs — official: in most cases faster and more reliable. Do not tick retain IDs on a board that already has introductions and a staff room. You will collide.
Import log table: a new or empty table name, official suggestion import_log (lowercase, digits, underscores). Redirect scripts use this log later. 301s. vBulletin has a dedicated XenForo Redirects product. Other sources vary. Keep the log.
User merge: usually asked if the importer creates users. Same email — usually yes (two rows with one email are usually one person). Same username — depends whether Admin on both sides is the same human. Official example: merging avoids Admin2.
vBulletin-class notes (overview only): if avatars or attachments live on disk, you must give the full system path. Guess-and-check is how you import a board with no files.
Browser or CLI
Official two runners:
| Method | How | Speed | Interaction |
|---|---|---|---|
| Browser | Start import, prompt each step | Slower | You click through counters |
| CLI | From the XF root (the directory that contains cmd.php): php cmd.php xf:import |
Significantly faster | All steps sequential |
Both are resumable. Official: you can resume via Tools → Import data or by running the CLI command again. Aim not to interrupt; some data may be lost. Leave the browser on the Start import page when you switch to CLI so the configuration you just saved is the one the command runs.
When the import completes, XenForo rebuilds caches. That is a job, not a superstition. Do not start it at peak next to a permission save. Community: permission compilation scales with groups × nodes. An import that also creates groups and nodes can lock a large tree. Off-peak.
Then: Board URL, cookie path, a guest / Registered / staff pass, one old avatar, search rebuild if the importer told you to. Appearance → Outdated templates only if you also changed XF version in the same window — do not mix import and upgrade in one night if you can help it.
What usually looks like a restore bug
| They say | You check first | Then |
|---|---|---|
| “Fresh install wizard after I uploaded files” | internal_data/install-lock.php missing |
Files replaced instead of merged |
| “No upgrade found” | You uploaded the upload/ folder itself |
Contents of upload/ must overwrite admin.php |
| “Everyone is a guest” | Cookie path / Board URL | Guest page cache serving members |
| “Avatars and attachments gone” | Empty data/ or internal_data/ |
Restore those archives; there is no rebuild |
| “SQL on the page” | $config['debug'] copied from staging |
Set false |
| “Login 400 on Discord / payments” | Board URL slash, http vs https, www vs apex | One canonical + 301 |
| “Import created Admin2” | Same-username merge was off | Expected if you declined the merge |
| “Retain IDs failed / collided” | Board was not empty | Official: empty of threads and posts only |
| “Import is still running tomorrow” | Browser runner on a remote source DB | CLI, both DBs local |
| “Search empty after restore” | Search index omitted or not rebuilt | Rebuild job; not a missing data/ |
Checklists
Before an upgrade
- Dump the database off-box.
- Archive
data/andinternal_data/. - Copy
src/config.phpand the add-on list. - Confirm you can restore that trio onto a clone tonight.
- Confirm 2.3 (or target) builds for add-ons you will re-enable.
- Tools → Upgrade check sees the license.
- You cannot downgrade. If the clone is not restored-and-working, you do not click production.
Before a host move
- Board active off.
- Final dump + final file archives.
- Same XF version on the destination.
- Board URL and cookie path written down for after.
- Mail and payment profiles considered (do not charge from a test URL).
- DNS TTL lowered yesterday, not today.
- Old box kept until the new box has a day of logs.
Before an import
- Importer add-on installed from the Customer area.
- Source notes read (vBulletin paths; phpBB details later).
- XF backup taken (DB +
data/+internal_data/). - Board active off.
- Steps selected; retain IDs only if the board has no threads/posts.
import_logtable name you will keep.- CLI from the directory that contains
cmd.php, if you have shell. - Caches and search planned for after, off-peak.
After any of the three
install-lock.phppresent.- One old avatar, one old attachment.
- Login survives refresh (three sessions).
- Cron last-run is moving.
- Debug off.
- Board URL is the URL in the address bar.
What this is not
It is not a phpBB 3.2–3.3 field map. Official range is 3.2 to 3.3; community has landed 3.3.15 on XF 2.3.10. Redirects, retain IDs, and phpBB-specific steps wait for that article.
It is not a Core Web Vitals pass. Gzip, Redis, and page cache are the speed article. After a move you only need them not to lie (wrong cookie + page cache).
It is not a security hardening guide. 2FA, login limits, and security lock are a later topic. Backup is still the control that makes those guides recoverable.
Takeaways
- Backup is database +
data/+internal_data/. The PHP files without those two directories are a demo. - Restore onto the same XenForo version, then fix Board URL and cookie path.
- Missing
install-lock.phpis a fresh-install wizard. Missingdata/is missing avatars. Neither is “rebuild caches.” - Official upgrade cannot downgrade. The restore is the undo.
- Importers are a separate add-on. Tools → Import data, or
php cmd.php xf:importfrom the XF root. Retain IDs only on an empty board. - Close Board active while you copy. Prove the backup by restoring it once before you need it.
If you cannot put last night’s members back this morning, you do not have a backup. You have a zip. Take the other two folders. Then take a walk, restore the zip onto a clone, and only then book the window.

