WordPress Staging on openSUSE Leap for Safer Store Updates

Why staging matters before a WordPress update
WordPress staging on openSUSE Leap gives you a safe copy of a live site. You can test plugin updates, theme changes, checkout fixes, and PHP adjustments before customers see them. For stores and content sites with real traffic, that usually means fewer rollback calls and fewer support tickets after a release.
In this tutorial, you will build a production-style staging environment on openSUSE Leap 15.6. You will protect it behind HTTP basic authentication, clone a WordPress site into a separate database, and verify that the staging copy runs cleanly before you promote changes. If you are hosting with Hostperl VPS, this is the same pattern many customers use for safer launch windows and agency handoffs.
This guide uses Nginx, MariaDB, PHP-FPM, and systemd on openSUSE Leap because that stack fits the OS well. It also keeps the procedure close to what you would run on a small production VPS. For a broader content refresh workflow, you can also pair this with WordPress migration checklist for safer store cutovers and WordPress staging for safe updates and cutovers.
What you will build
You will create a staging site at staging.example.com on the same VPS or a separate server. It will point at a cloned database and a copied WordPress file tree. The staging site will stay isolated from public access, protected with a login prompt, and ready for testing plugin updates, WooCommerce changes, or theme edits.
- openSUSE Leap 15.6
- Nginx serving the staging virtual host
- MariaDB for the cloned database
- PHP-FPM for WordPress execution
- Optional Nginx basic auth to keep staging private
Use this for a fresh server or a controlled clone of your production site. If you are testing a WooCommerce store, keep payment gateways in sandbox mode and disable real order emails until you finish verification.
Log in and detect the operating system
On your local computer: connect to the server with the documentation IP below. Replace 203.0.113.10 with your own server IP from Hostperl or your provider.
ssh root@203.0.113.10If your server uses a custom SSH port, use ssh -p 2222 root@203.0.113.10 instead. Keep this root session open until the new administrator login works.
On the VPS as root: detect the OS before you install anything.
cat /etc/os-releaseYou should see openSUSE Leap in the output. This tutorial is written for that platform because it supports zypper, systemd, firewalld, and AppArmor cleanly.
Create a sudo user and prepare SSH access
Run the following commands to create a non-root administrator named deploy. This keeps day-to-day work away from the root account.
On the VPS as root:
useradd -m -G wheel -s /bin/bash deploy
passwd deploy
mkdir -p /home/deploy/.ssh
chmod 700 /home/deploy/.ssh
cp /root/.ssh/authorized_keys /home/deploy/.ssh/authorized_keys
chown -R deploy:deploy /home/deploy/.ssh
chmod 600 /home/deploy/.ssh/authorized_keysThis creates the account, sets a password, copies your existing SSH key if root already uses one, and locks down the SSH directory. If root does not have an authorized key file yet, create it from your local terminal with ssh-copy-id deploy@203.0.113.10 after you create the account.
Now allow the wheel group to use sudo.
visudoUncomment or add this line, then save and exit:
%wheel ALL=(ALL) ALLOn your local computer: open a second terminal and test the new login.
ssh deploy@203.0.113.10Then test sudo.
sudo -vYou should be prompted for the deploy password and then returned to the shell without an error. Do not disable root login until this works.
Update the server and install the WordPress stack
On the VPS as the non-root sudo user:
sudo zypper refresh
sudo zypper update -y
sudo zypper install -y nginx mariadb mariadb-client php8-fpm php8-mysql php8-gd php8-curl php8-xml php8-mbstring php8-zip php8-opcache php8-intl php8-imagick php8-cli unzip wget tar firewalld
php -v
nginx -v
mariadbd --versionThese commands refresh package metadata, update the base system, and install the services needed for WordPress. The version checks confirm that PHP, Nginx, and MariaDB are available before you continue.
Enable and start the services you will use.
sudo systemctl enable --now nginx mariadb php-fpm firewalldOn openSUSE Leap, the PHP-FPM service name is usually php-fpm. Confirm it if your package set differs.
Harden MariaDB for staging
On the VPS as the non-root sudo user: run the built-in secure setup.
sudo mysql_secure_installationSet a root password for MariaDB if prompted, remove anonymous users, disallow remote root login, and remove the test database. This does not affect your WordPress database. It simply reduces exposure.
Now create separate databases for production and staging. Even if you are cloning a live site, keep the staging database isolated.
sudo mysql -u root -pAt the MariaDB prompt, run:
CREATE DATABASE wordpress_prod CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
CREATE DATABASE wordpress_stage CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
CREATE USER 'wp_prod'@'localhost' IDENTIFIED BY 'Use-A-Long-Unique-Password-Here-1!';
CREATE USER 'wp_stage'@'localhost' IDENTIFIED BY 'Use-A-Long-Unique-Password-Here-2!';
GRANT ALL PRIVILEGES ON wordpress_prod.* TO 'wp_prod'@'localhost';
GRANT ALL PRIVILEGES ON wordpress_stage.* TO 'wp_stage'@'localhost';
FLUSH PRIVILEGES;
EXIT;Replace both example passwords with long unique values. If you are moving a real store, keep these passwords in a password manager and do not reuse the production password on staging.
Install WordPress files and create the staging virtual host
Create the document roots first.
sudo mkdir -p /srv/www/wordpress-prod /srv/www/wordpress-stageIf you already have a production site on this server, point the production path at that existing directory instead of copying files again.
Download WordPress and place one copy in each location.
cd /tmp
wget https://wordpress.org/latest.tar.gz
tar -xzf latest.tar.gz
sudo rsync -a wordpress/ /srv/www/wordpress-prod/
sudo rsync -a wordpress/ /srv/www/wordpress-stage/Next, set ownership for the web server.
sudo chown -R wwwrun:www /srv/www/wordpress-prod /srv/www/wordpress-stageopenSUSE Leap usually runs Nginx as wwwrun. That ownership lets the web server and PHP-FPM read the files without making them world-writable.
Create the Nginx site configuration for staging.
sudo mkdir -p /etc/nginx/vhosts.d
sudo nano /etc/nginx/vhosts.d/staging.example.com.confPaste this full virtual host file, then save and exit:
server {
listen 80;
server_name staging.example.com;
root /srv/www/wordpress-stage;
index index.php index.html;
auth_basic "Staging Area";
auth_basic_user_file /etc/nginx/.htpasswd-staging;
location / {
try_files $uri $uri/ /index.php?$args;
}
location ~ \.php$ {
include fastcgi_params;
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
fastcgi_pass unix:/run/php-fpm/www.sock;
}
location ~* \.(js|css|png|jpg|jpeg|gif|ico|svg)$ {
expires 30d;
access_log off;
}
}Create the password file for staging access.
sudo zypper install -y apache2-utils
sudo htpasswd -c /etc/nginx/.htpasswd-staging stagingadminEnter a strong password when prompted. This keeps the staging copy out of search engines and away from casual browsing.
Now add the site to the main Nginx config if needed. On many openSUSE builds, files in /etc/nginx/vhosts.d/ load automatically. Confirm the syntax before reloading.
sudo nginx -tYou should see syntax is ok and test is successful. If that passes, reload Nginx.
sudo systemctl reload nginxPrepare WordPress configuration for production and staging
For each site, create a wp-config.php file from the sample and set the database credentials.
cd /srv/www/wordpress-prod
sudo cp wp-config-sample.php wp-config.php
sudo nano wp-config.phpChange the database lines to match the production database you created or already use:
define( 'DB_NAME', 'wordpress_prod' );
define( 'DB_USER', 'wp_prod' );
define( 'DB_PASSWORD', 'Use-A-Long-Unique-Password-Here-1!' );
define( 'DB_HOST', 'localhost' );Repeat the same pattern for staging, but point it at wordpress_stage and wp_stage.
cd /srv/www/wordpress-stage
sudo cp wp-config-sample.php wp-config.php
sudo nano wp-config.phpAdd unique salts later through the WordPress secret key generator if you are cloning a live database. Keep the table prefixes the same only if you are copying the entire database exactly.
Clone the live database into staging
If you already have a production site on this server, export it and import it into the staging database. Replace the file paths with your real backup names if you are migrating from elsewhere.
sudo mysqldump -u root -p wordpress_prod | sudo mysql -u root -p wordpress_stageThis is the safest simple approach for a same-server clone. For a large store, run the import during a low-traffic window because it can use significant disk I/O.
Update the site URL inside the staging database so WordPress does not redirect to production.
sudo mysql -u root -p wordpress_stageInside the MariaDB shell, run:
UPDATE wp_options SET option_value = 'https://staging.example.com' WHERE option_name IN ('siteurl','home');
EXIT;If your table prefix is not wp_, replace it with your actual prefix. After the update, the staging site should load as its own site rather than following the production domain.
Set firewall rules and SELinux/AppArmor checks
Open the web ports before testing from a browser.
sudo firewall-cmd --permanent --add-service=http
sudo firewall-cmd --permanent --add-service=https
sudo firewall-cmd --reload
sudo firewall-cmd --list-allThe list output should show http and https. openSUSE Leap uses AppArmor by default, so you normally do not need SELinux changes here. If Nginx cannot read a file, check ownership first rather than guessing at policy changes.
Test the site from the server and from a client
On the VPS as the non-root sudo user:
curl -I http://127.0.0.1 -H 'Host: staging.example.com'You should receive an HTTP 200 or a redirect to the WordPress installer. If you get a 502, check PHP-FPM next.
sudo systemctl status php-fpm --no-pager
sudo journalctl -u php-fpm -n 50 --no-pagerA healthy PHP-FPM service should show active (running). If the socket path in Nginx does not match the one PHP-FPM created, correct the fastcgi_pass line in the virtual host file.
On your local computer: browse to http://staging.example.com and log in with the staging basic-auth username and password. If DNS has not been pointed yet, you can test with your hosts file or with a temporary local resolver entry.
After WordPress loads, sign in to the admin area and run a quick smoke test:
- Open a post or page
- Upload one image
- Save permalinks again
- Load the checkout page if WooCommerce is installed
For WooCommerce, place a sandbox test order and verify that the order reaches the dashboard without sending a live payment request.
Disable risky actions and keep staging private
Staging should never be indexed or treated like a public demo site. Add a robots block and keep the basic-auth prompt in place.
sudo tee /srv/www/wordpress-stage/robots.txt >/dev/null <<'EOF'
User-agent: *
Disallow: /
EOF
sudo chown wwwrun:www /srv/www/wordpress-stage/robots.txtIf you later issue TLS for staging, keep the same access control and do not remove the password prompt. Search engines should not discover this site, and customers should not be able to guess a test login page.
Rollback plan if an update breaks the site
The advantage of staging is that rollback stays predictable. Before you apply a risky plugin or theme update to production, take these backups:
sudo mysqldump -u root -p wordpress_prod > /root/wordpress_prod-$(date +%F).sql
sudo tar -czf /root/wordpress_prod-files-$(date +%F).tar.gz /srv/www/wordpress-prodIf the update fails on staging, restore the database and files from those backups. Then retest the site locally before promoting anything. If the problem is a plugin conflict, disable the plugin by renaming its directory under wp-content/plugins and reload the page.
Final verification and reboot test
On the VPS as the non-root sudo user:
sudo systemctl status nginx mariadb php-fpm firewalld --no-pager
sudo ss -tulpn | grep -E ':80|:443|:3306'
sudo rebootAfter the server comes back, reconnect with SSH and confirm the services are still active. You should also see that port 80 is listening, the staging site still responds, and the password prompt still protects it. That reboot check matters because WordPress staging only helps if the stack survives maintenance windows.
If you are running this on a Hostperl VPS or a larger dedicated server hosting plan, the same layout scales well for agencies and store owners who need a safer release process. For larger rollouts, Hostperl also offers managed VPS hosting options that fit staging, backups, and cutover work without overcommitting to a big server on day one.
If you manage customer sites, staging is one of the cheapest ways to prevent avoidable outages. Hostperl VPS and dedicated server hosting both fit this workflow well because you can isolate test changes, verify them, and cut over only when the site is ready.
If you need help planning a safer WordPress rollout, the Hostperl team can help you size the server, choose the right storage, and keep the release process controlled.
Common problems and how to fix them
1. Nginx shows 502 Bad Gateway. Run sudo systemctl status php-fpm --no-pager and sudo journalctl -u php-fpm -n 50 --no-pager. If the socket path is wrong, update fastcgi_pass in the Nginx config and reload Nginx after sudo nginx -t.
2. WordPress redirects to the production domain. Check the siteurl and home values with sudo mysql -u root -p wordpress_stage -e "SELECT option_name, option_value FROM wp_options WHERE option_name IN ('siteurl','home');". If they still point to production, update them again.
3. Basic auth does not prompt. Run sudo ls -l /etc/nginx/.htpasswd-staging and confirm the Nginx config includes auth_basic and auth_basic_user_file. If the password file is missing, recreate it with sudo htpasswd -c /etc/nginx/.htpasswd-staging stagingadmin.
4. Files are not writable for uploads. Check ownership with sudo ls -ld /srv/www/wordpress-stage /srv/www/wordpress-stage/wp-content/uploads. The web server should own the writable directories, and you should avoid making the full tree writable.
FAQ
Can I use this staging method for WooCommerce?
Yes. Use sandbox payment settings, disable live email sending, and test checkout on staging before any theme or plugin update reaches production.
Should staging use the same database as production?
No. Always use a separate database. A shared database defeats the point of testing and can overwrite live orders or content.
Do I need TLS on staging?
Not always, but it is useful when you need to test logins, forms, or payment redirects. Keep the access prompt in place even if you add a certificate.
What if my WordPress site is on another server?
Export the files and database from production, copy them to the openSUSE Leap server, then follow the same database import and URL update steps.
Is this safe for agencies with multiple clients?
Yes, as long as each client gets its own staging database, its own document root, and its own access controls.
