jsonLd && ( ) Skip to content
All posts

Why Restoring a Big WordPress Backup Timed Out

Backups of a 25 GB store took seconds, but restoring one failed every time after about two minutes. Why restores are slower and what we changed.

In June a customer needed to roll their WooCommerce store back to the previous weekend. It was a large site, about 25 GB spread over 72,000 files, and every attempt to restore it from the dashboard failed after roughly two minutes with nothing restored. Backups of the same site had been running every night without a problem, and each one finished in a few seconds.

Why does restoring a WordPress backup take longer than making one?

We keep backups with Borg, which splits files into chunks and only uploads the chunks that changed since the last run. On a normal night very little of a store changes, so the nightly backup of that 25 GB site took about seven seconds. A restore has no such shortcut, because it has to pull the entire archive back down and write every file, and for this store that takes several minutes.

The dashboard ran that whole extract inside a single web request, so the request stayed open while Borg worked, and after about two minutes the connection was cut and Borg was killed along with it. We first went looking for a timeout to raise, but our own server and proxy already allowed ten minutes, so the cut came from somewhere further out between the dashboard and the browser. Raising a limit somewhere would only have moved the problem to the next bigger site.

What we changed

The restore button now only queues the job and returns straight away. A background worker does the extract with its own one-hour limit, and when the files are back it hands over to the step that imports the database, which already worked this way. A restore can take as long as it needs, and nothing depends on a browser tab staying open. Restores now also show their progress in the dashboard, and you can put back single files from a backup without restoring the whole site.

How to restore a large WordPress backup by hand

Until the change was released we restored that store by hand, and the order of the steps matters. We took a filesystem snapshot of the site first, so we could go back if anything went wrong, because a restore overwrites both the live files and the live database. Then we ran the Borg extract directly on the server into the site’s folder, outside of any web request:

cd /path/to/site && borg extract --lock-wait 300 "$REPO::$ARCHIVE" --strip-components 7

The --strip-components value depends on how deep the site’s folder sits inside your archive. The backup includes a database dump, which we imported with the site’s own database user. Then we deleted the dump file from the web root, since a leftover .sql file there can be downloaded by anyone who guesses its name. PHP noticed the changed files by itself within a couple of seconds, so no restart was needed.

If you restore big sites by hand, take a snapshot before you start and remove the database dump from the web root when you are done.

Related update: Restore Single Files From Your Backups