IPv4 & IPv6 Leasing - Any RIR, Any LocationOrder Now
Hostperl

WooCommerce Staging and Safe Cutover on openSUSE Leap

By Raman Kumar

Share:

Updated on Sep 2, 2026

WooCommerce Staging and Safe Cutover on openSUSE Leap

What this tutorial solves

WooCommerce staging gives you a safe place to test theme changes, plugin updates, payment settings, and checkout fixes before customers ever see them. On openSUSE Leap, you can build that workflow on a VPS with a clean production clone, a controlled database sync, and a cutover plan that lets you recover quickly if checkout breaks.

This guide is written for a fresh Hostperl VPS, using openSUSE Leap because the stack fits it well through zypper, systemd, firewalld, and AppArmor. If you are planning a production move, a Hostperl VPS gives you enough control for staging, backups, and launch testing without overspending on a small store. For related release planning, see WordPress migration rehearsal for safer 2026 cutovers and WordPress checkout recovery before launch.

Plan the staging layout first

Use two hostnames:

  • Production: example.com
  • Staging: staging.example.com

Keep the staging site private with HTTP basic auth or, at minimum, a noindex rule. The safest pattern is simple: clone the code and database, then test the exact checkout flow with a non-live payment method.

We will use these example paths:

  • Production web root: /srv/www/example.com
  • Staging web root: /srv/www/staging.example.com
  • Database: woocommerce_prod and woocommerce_stage
  • Admin user: deploy

Connect to the VPS and identify openSUSE Leap

On your local computer:

ssh root@203.0.113.10

203.0.113.10 is a reserved documentation address. Replace it with the real public IP assigned by your provider.

On the VPS as root:

cat /etc/os-release

You should see openSUSE Leap in the output. If you do not, stop here and use the matching distribution instructions for your server image.

Create a non-root admin and keep root open until it works

On the VPS as root:

useradd -m -s /bin/bash deploy
passwd deploy
usermod -aG wheel deploy
mkdir -p /home/deploy/.ssh
chmod 700 /home/deploy/.ssh
cat /root/.ssh/authorized_keys > /home/deploy/.ssh/authorized_keys
chown -R deploy:deploy /home/deploy/.ssh
chmod 600 /home/deploy/.ssh/authorized_keys

This creates the deploy account, sets a password for first access, adds sudo rights through the wheel group, and copies the root SSH key so you can log in safely. Keep the root session open until the new login is verified.

On your local computer, open a second terminal:

ssh deploy@203.0.113.10

Then test sudo:

sudo -v
whoami

You should see deploy from whoami. Only after this works should you consider disabling root password login in /etc/ssh/sshd_config.

Update the server and install the WooCommerce stack

On the VPS as the non-root sudo user:

sudo zypper refresh
sudo zypper update -y
sudo zypper install -y nginx mariadb-server php-fpm php-mysql php-gd php-intl php-zip php-curl php-mbstring php-opcache php-xml php-soap php-cli php-sodium certbot python3-certbot-nginx firewalld

This installs the web server, database, PHP runtime, TLS tooling, and the firewall. openSUSE Leap uses zypper, not apt or dnf.

Check versions so you know exactly what is running:

nginx -v
php -v
mysql --version

Start services and open the firewall

On the VPS as root:

systemctl enable --now nginx mariadb php-fpm firewalld
firewall-cmd --permanent --add-service=http
firewall-cmd --permanent --add-service=https
firewall-cmd --reload

Open the firewall before exposing the site. If you use SSH on the default port 22, leave it untouched.

Verify service state:

systemctl status nginx mariadb php-fpm --no-pager

Harden MariaDB for production and create databases

On the VPS as root:

mysql_secure_installation

Choose a strong root password, remove anonymous users, disallow remote root login, remove the test database, and reload privilege tables.

Now create separate production and staging databases and a limited user:

mysql -u root -p

Run the following inside the MariaDB prompt:

CREATE DATABASE woocommerce_prod CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
CREATE DATABASE woocommerce_stage CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
CREATE USER 'wcuser'@'localhost' IDENTIFIED BY 'Use-A-Long-Unique-Password-Here';
GRANT ALL PRIVILEGES ON woocommerce_prod.* TO 'wcuser'@'localhost';
GRANT ALL PRIVILEGES ON woocommerce_stage.* TO 'wcuser'@'localhost';
FLUSH PRIVILEGES;
EXIT;

The same user can access both databases locally. Keep the password private and do not store it in the web root.

Install WordPress for production, then clone it for staging

On the VPS as the non-root sudo user:

sudo mkdir -p /srv/www/example.com /srv/www/staging.example.com
sudo chown -R deploy:nginx /srv/www

Download WordPress and move it into the production tree:

cd /tmp
curl -LO https://wordpress.org/latest.tar.gz
tar -xzf latest.tar.gz
sudo rsync -a wordpress/ /srv/www/example.com/

Create the production configuration:

sudo cp /srv/www/example.com/wp-config-sample.php /srv/www/example.com/wp-config.php
sudo nano /srv/www/example.com/wp-config.php

Replace the database section with:

define( 'DB_NAME', 'woocommerce_prod' );
define( 'DB_USER', 'wcuser' );
define( 'DB_PASSWORD', 'Use-A-Long-Unique-Password-Here' );
define( 'DB_HOST', 'localhost' );
define( 'DB_CHARSET', 'utf8mb4' );
define( 'DB_COLLATE', '' );

Save and exit. Then lock permissions:

sudo chown -R deploy:nginx /srv/www/example.com
sudo find /srv/www/example.com -type d -exec chmod 755 {} \;
sudo find /srv/www/example.com -type f -exec chmod 644 {} \;
sudo chmod 640 /srv/www/example.com/wp-config.php

Install the site through your browser at http://example.com after DNS points at the VPS. Finish the WordPress installer, then install WooCommerce from the dashboard.

For staging, clone the production tree and database. Dump and import the database first:

mysqldump -u root -p woocommerce_prod | mysql -u root -p woocommerce_stage
sudo rsync -a --delete /srv/www/example.com/ /srv/www/staging.example.com/

Now update the staging config to use the staging database:

sudo cp /srv/www/staging.example.com/wp-config.php /srv/www/staging.example.com/wp-config.php.bak
sudo nano /srv/www/staging.example.com/wp-config.php

Change only the database name if both use the same local user:

define( 'DB_NAME', 'woocommerce_stage' );

Protect WooCommerce staging from search engines and customers

On the VPS as the non-root sudo user:

sudo nano /srv/www/staging.example.com/.htaccess

Add this if you want an Apache-style noindex rule; for Nginx, you will use a server block header instead. Save the file only if your stack actually serves .htaccess.

For Nginx, create a staging server block with basic auth and noindex headers:

sudo nano /etc/nginx/vhosts.d/staging.example.com.conf

Use this content:

server {
    listen 80;
    server_name staging.example.com;
    root /srv/www/staging.example.com;
    index index.php index.html;

    add_header X-Robots-Tag "noindex, nofollow" always;

    location / {
        try_files $uri $uri/ /index.php?$args;
    }

    location ~ \.php$ {
        include fastcgi_params;
        fastcgi_pass 127.0.0.1:9000;
        fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
    }
}

Check syntax before reload:

sudo nginx -t
sudo systemctl reload nginx

For basic auth, generate credentials and add the auth directives if you want extra privacy. If you do not enable it, keep the staging hostname unlinked and blocked by noindex.

Set PHP limits that fit WooCommerce staging

On the VPS as the non-root sudo user:

sudo grep -nE '^(memory_limit|max_execution_time|upload_max_filesize|post_max_size)' /etc/php*/fpm/php.ini

On openSUSE Leap, the path may vary by PHP version. Edit the active file reported by the command:

sudo nano /etc/php8/fpm/php.ini

Use values that work for media uploads and checkout plugins:

memory_limit = 256M
max_execution_time = 120
upload_max_filesize = 64M
post_max_size = 64M

Then reload PHP-FPM after a syntax-safe edit:

sudo systemctl restart php-fpm

Enable HTTPS with Let's Encrypt

On the VPS as root:

certbot --nginx -d example.com -d www.example.com

Repeat for staging only if you have a reason to expose it publicly:

certbot --nginx -d staging.example.com

Certbot edits the Nginx config and reloads it. Confirm renewal works:

systemctl status certbot-renew.timer --no-pager
certbot renew --dry-run

Run checkout tests before you cut over

Do not trust the homepage alone. Test the cart, checkout page, order email, and the payment gateway you will actually use.

On your local computer:

curl -I https://staging.example.com
curl -s https://staging.example.com | grep -iE 'woocommerce|cart|checkout|noindex'

On the server, look for PHP or Nginx errors if anything fails:

sudo tail -n 50 /var/log/nginx/error.log
sudo journalctl -u php-fpm -n 50 --no-pager

For a functional test, place a real test order using the store's sandbox payment mode and verify:

  • Order appears in WooCommerce
  • Customer receives confirmation email
  • Stock changes correctly
  • Order status changes after payment capture

Cut over from staging to production safely

When staging passes, freeze content briefly, take a backup, then move the final database and uploads. This is the point where many store outages happen if people skip the rehearsal.

On the VPS as root:

mysqldump -u root -p woocommerce_prod > /root/woocommerce_prod-$(date +%F).sql
cp -a /srv/www/example.com/wp-content/uploads /root/uploads-backup-$(date +%F)

If you need a rollback, restore the SQL dump and uploads directory, then switch DNS or the vhost back to the previous state.

After the final content sync, clear cache inside WordPress and your caching plugin. Then retest the live URL, checkout, and email flow from a second browser or mobile network.

Rollback and recovery path

If checkout breaks after deployment, do not keep editing live. Roll back in this order:

  1. Disable maintenance mode only if it is preventing access to the admin.
  2. Restore the previous database dump.
  3. Restore wp-content if plugin or theme files were changed.
  4. Revert the Nginx vhost or PHP settings that changed.
  5. Reload services and retest the full purchase flow.

Useful restore commands:

mysql -u root -p woocommerce_prod < /root/woocommerce_prod-2026-09-02.sql
sudo rsync -a /root/uploads-backup-2026-09-02/ /srv/www/example.com/wp-content/uploads/
sudo systemctl reload nginx
sudo systemctl restart php-fpm

Troubleshooting the most likely failures

1) Staging site shows 502 Bad Gateway

Diagnostic:

sudo systemctl status php-fpm --no-pager
sudo journalctl -u php-fpm -n 100 --no-pager

Expected clue: PHP-FPM is stopped, crashed, or listening on the wrong socket. Fix by correcting the PHP-FPM pool config and restarting the service.

2) Checkout page loads but payment fails

Diagnostic:

sudo tail -n 100 /var/log/nginx/error.log
sudo tail -n 100 /srv/www/example.com/wp-content/debug.log

Expected clue: plugin, REST API, or TLS errors. Next step: disable the most recent payment or caching plugin on staging first, then retest.

3) Email confirmations do not arrive

Diagnostic:

sudo journalctl -u postfix -n 50 --no-pager
sudo grep -i "mail" /var/log/messages | tail -n 50

Expected clue: no mail transfer agent is configured, or the provider blocks outbound SMTP. Fix by using a proper SMTP relay and rechecking SPF, DKIM, and DMARC for the domain.

Reboot-persistence checks

Before calling the migration done, reboot once and prove the stack returns cleanly:

sudo reboot

After reconnecting, check:

systemctl is-enabled nginx mariadb php-fpm firewalld
systemctl status nginx mariadb php-fpm firewalld --no-pager
curl -I https://example.com

You want all services enabled and the site to answer over HTTPS after reboot.

If you want a clean launch path for WooCommerce, Hostperl VPS hosting gives you the control needed for staging, database backups, and TLS without overspending. For stores that need steady support during migration week, a managed VPS hosting plan can reduce the risk of a rushed cutover.

Hostperl's support team is a good fit when you need help validating DNS, SSL, or a checkout issue before customers notice it.

FAQ

Can I keep staging private without blocking the live store?

Yes. Put staging on its own hostname, add noindex headers, and protect it with basic auth or IP access rules. Do not share the same database with production.

Should I clone payments to staging?

Use sandbox or test-mode credentials only. Never let staging talk to a live payment gateway unless the provider explicitly supports that setup.

What is the safest backup point before cutover?

Take a database dump and copy wp-content/uploads immediately before the final sync. Those two items cover most rollback cases after a bad plugin update or checkout regression.

Can I run this on a smaller VPS?

Yes, if the store is light. For media-heavy stores or update windows with many concurrent shoppers, choose enough RAM for PHP-FPM and MariaDB headroom, not just the lowest price.