Learn / Setting Up a Staging Site

Setting Up a Staging Site

GUIDE

7 min read · 1,635 words

A staging site is a private copy where you can break things safely. It is the cheapest insurance you can buy.

A staging site is a private copy of your website where you can break things safely. You apply the update, try the redesign, install the unfamiliar plugin, and watch what happens, while the real site carries on serving real visitors. If the experiment goes wrong, you delete the copy and start again. If it goes right, you repeat the change on the live site with a good deal more confidence than you had an hour earlier.

It is the cheapest insurance in web hosting. A copy costs a few hundred megabytes of disk space and about half an hour of your time, and it saves the sort of evening that begins with a white screen and a customer email. Most of the support tickets I have seen titled "the site is down after the update" would have been a non-event on a staging copy.

This guide walks through building one by hand, which works on any host, then covers locking it down, testing on it, moving changes across, and keeping it from becoming a liability. If your host has a one-click staging button, the steps below still describe what that button does, which is useful when it does something unexpected.

What staging has to be

The whole point of a staging site is that it behaves like the live one. A copy that differs in important ways will pass tests that the live site then fails. So before you build anything, decide what "the same" means for your site.

The files and the database should come from live, recently. The PHP version should match, along with the web server (Apache or nginx), the memory limit and the major extensions. The same plugins and theme should be active at the same versions. What should not match is everything that touches the outside world: real email, real payments, search engine access, and the public.

Live site example.com Copy files and database Staging site locked down Test the change works? repeat on live, with a fresh backup broken? delete the copy and rebuild it from live
The staging loop: copy from live, lock the copy down, test, then repeat the change on live.

Step by step: building the copy by hand

These steps assume a typical shared or VPS account with SSH, a control panel for databases, and WordPress as the application. The shape is the same for other PHP applications; only the configuration file changes.

  1. Create a subdomain, staging.example.com, in your control panel, with its own document root, for example /home/example/staging. Check that DNS resolves it with dig +short staging.example.com.
  2. Create a new, empty database and a new database user for it. Never point staging at the live database, not even temporarily. This is the single most expensive mistake available.
  3. Copy the files: cp -a /home/example/public_html/. /home/example/staging/. The -a keeps permissions and timestamps.
  4. Dump the live database and load it into the new one:
mysqldump -u live_user -p live_db > live.sql
mysql -u stg_user -p stg_db < live.sql
  1. Edit /home/example/staging/wp-config.php so it uses the new database name, user and password. Add define('WP_ENVIRONMENT_TYPE', 'staging'); so plugins that care can tell where they are.
  2. Rewrite the addresses stored in the database (next section).
  3. Lock the copy down (the section after that) before you open it in a browser.

Rewriting addresses without corrupting data

WordPress stores its own address in the database, and a good many plugins store full URLs in options, widgets and page-builder content. If you leave them alone, the staging site will load its stylesheets from the live site, or redirect you straight back to it. That makes for a confusing afternoon in which you edit one site while looking at the other.

Much of that data is serialised: a PHP string such as s:24:"https://example.com/logo" records its own length. A plain find-and-replace in a text editor changes the text but not the length, and the value silently stops loading. WP-CLI's search-replace understands serialised data and fixes the lengths as it goes:

wp search-replace 'https://example.com' 'https://staging.example.com' \
  --all-tables --skip-columns=guid --dry-run
wp search-replace 'https://example.com' 'https://staging.example.com' \
  --all-tables --skip-columns=guid

Run the dry run first and read the counts. Skipping the guid column is deliberate: those values are permanent identifiers for feeds, not links. Without WP-CLI, a dedicated search-replace tool that handles serialised data does the same job; a raw SQL UPDATE ... REPLACE() does not.

If the site also used http:// addresses in old content, or a www variant, run the replacement for each form you find. Check with wp db query "SELECT COUNT(*) FROM wp_posts WHERE post_content LIKE '%example.com%'" afterwards.

Locking the copy down

An open staging site causes three separate kinds of trouble. Search engines index it, so you end up with a duplicate of your own site competing against you. Strangers find it, and an unpatched test copy is an easy target. And it can send real email, charge real cards or call real services, because it holds live credentials.

Work through these in order, before anyone loads a page:

Live site Staging copy Search engines may index blocked, noindex Email sends to customers suppressed or trapped Payments live gateway keys sandbox keys only Visitors public password required
What should differ between the live site and its staging copy.

What changes between hosting types

How much of this you do yourself depends on where the site lives.

HostingTypical staging routeWatch for
SharedPanel tool or manual subdomain copySame PHP version is usually enforced per domain; check it, as a subdomain can be set differently
VPSA second virtual host on the same server, or a separate small serverA staging site on the same server shares its CPU and memory, so a heavy test can slow live

Testing on the copy

Apply the change you came to test, then walk through the paths that make money or cause support tickets. Log in and out. Submit each form and confirm where the message would have gone. Search for something. Add a product to a basket and get as far as the payment page. Open some old posts, a category page and the home page on a phone-sized window.

Then read the logs, because many faults do not show on screen. Turn on debugging on staging only: define('WP_DEBUG', true); define('WP_DEBUG_LOG', true);, then tail -f wp-content/debug.log while you click around. Deprecation notices about a plugin are an early warning that the next PHP version will break it. The web server's error log, usually under logs/ or /var/log/, is the other place to look.

Getting the change onto live

There are two honest ways to do this, and the right one depends on what kind of change you made.

For updates and settings changes, repeat the steps on live. Take a fresh backup, pick a quiet hour, and apply the same updates in the same order. This is slower than pushing a copy across, but nothing on the live site is overwritten, and any orders or comments that arrived while you were testing are safe.

For a redesign or a large structural change, you may push the staging files and database over live. That is only safe if the live content has not changed since you copied it. On a brochure site that is easy to guarantee. On a shop, a forum or a busy blog, it is not: you would wipe out every order, signup and comment since the copy. In that case, push the code and theme files across, and apply database changes by hand or with a migration tool.

Keeping staging useful and then removing it

A staging copy that is three months old tests nothing, because live has moved on. Refresh it from live before each round of changes: re-export the database, re-run the search-replace, and copy changed files.

When you are finished, delete the copy: the files, the database, the database user and the subdomain. An old, forgotten staging site is usually running outdated plugins, often with a weak password, and holding a full copy of your customer data. I have seen more than one breach that started on a test site nobody remembered.

Commands worth running

Smaller questions

Is a staging plugin as good as doing it by hand?

For most small sites, yes. The plugin does the same copy and search-replace for you. Look at what it does with email, indexing and scheduled tasks, because those defaults vary.

Does staging protect me from every bad update?

No. It catches faults that show up in the copy. Problems that depend on real traffic, real data volume or timing may only appear on live, which is why a backup is still non-negotiable.

Checklist