Why this workflow matters
This tutorial shows how to build a clean WordPress staging site on a fresh dedicated server, test changes safely, and promote the site to production with minimal risk. It is aimed at hosting customers who need a repeatable process for updates, redesigns, plugin changes, and content validation before a live launch. You will set up the server, install the required packages, create the database, deploy WordPress in a staging directory, add a reverse proxy, secure the site with TLS, and then move the site into production after verification.
Use a dedicated server for this workflow, especially if you want full root access, NVMe storage, and room for a proper staging and production split. If you are still choosing hardware, start with HostnExtra dedicated servers. For broader planning, these guides are also useful: How to Choose a Dedicated Server in 2026, How to Compare Dedicated Server Options in 2026, and Backup Restore Testing on Linux Dedicated Servers.
Prerequisites and server plan
- One dedicated server running Ubuntu 26.04 LTS, Debian 13, AlmaLinux 10, or Rocky Linux 10.
- One public IPv4 address and, if available, IPv6.
- A DNS name for staging, such as staging.example.com.
- Optional production name, such as www.example.com.
- Minimum starting resources for a small WordPress site: 2 vCPU, 4 GB RAM, and SSD or NVMe storage.
- Ports required: 22 for SSH, 80 for HTTP, and 443 for HTTPS.
Replace these placeholders throughout the tutorial:
- SERVER_IP=203.0.113.10
- ADMIN_USER=deploy
- DOMAIN_NAME=staging.example.com
- PROD_DOMAIN=www.example.com
- APP_DIR=/var/www/wordpress-staging
- DB_NAME=wordpress_staging
- DB_USER=wpuser
Connect, detect the operating system, and create a sudo user
The first SSH command runs on your local computer. Keep the original root session open until the new account is tested and working.
ssh [email protected]If your server uses a custom SSH port, connect with it explicitly from your local computer:
ssh -p 2222 [email protected]On the VPS as root, confirm the distribution before you install anything:
cat /etc/os-releaseYou should see the OS name and version. Use the matching package and firewall section below.
Now create a non-root admin account on the VPS as root. Replace deploy with your chosen username.
useradd -m -s /bin/bash deploy
passwd deploySet a strong password when prompted. Then add the user to the admin group. On Debian-family systems, use sudo. On AlmaLinux and Rocky Linux, use wheel.
Ubuntu / Debian as root:
usermod -aG sudo deployAlmaLinux / Rocky Linux as root:
usermod -aG wheel deployCreate the SSH directory and copy your public key from your local computer. Replace the example key path with your own file.
On the VPS as root:
mkdir -p /home/deploy/.ssh
chmod 700 /home/deploy/.ssh
touch /home/deploy/.ssh/authorized_keys
chmod 600 /home/deploy/.ssh/authorized_keys
chown -R deploy:deploy /home/deploy/.sshOn your local computer:
cat ~/.ssh/id_ed25519.pubCopy the output, paste it into /home/deploy/.ssh/authorized_keys on the VPS, save the file, and confirm permissions again on the VPS as root:
ls -ld /home/deploy/.ssh
ls -l /home/deploy/.ssh/authorized_keysYou want directory permissions of 700 and file permissions of 600.
Open a second local terminal and test the new account before touching root login settings:
ssh [email protected]From the new session on the VPS as deploy, test sudo:
sudo -vIf sudo asks for your password and succeeds, the account is ready. Keep the original root session open.
Update packages, sync time, and prepare the firewall
Run the package update commands that match your operating system. Do this on the VPS as root or through sudo, depending on your preference.
Ubuntu / Debian:
apt update
apt -y upgrade
apt -y install ca-certificates curl gnupg unzip lsb-release ufw mysql-server nginx php-fpm php-mysql php-cli php-curl php-xml php-mbstring php-zip php-gd php-intlThese commands refresh package indexes, apply updates, and install the software needed for WordPress, Nginx, and PHP.
AlmaLinux / Rocky Linux:
dnf -y update
dnf -y install ca-certificates curl unzip policycoreutils-python-utils firewalld nginx php-fpm php-mysqlnd php-cli php-curl php-xml php-mbstring php-zip php-gd php-intl mariadb-serverOn RHEL-compatible systems, firewalld and SELinux tooling are part of the standard setup.
Check time synchronization and enable it:
timedatectl status
systemctl enable --now systemd-timesyncd || systemctl enable --now chronydOn Ubuntu and Debian, systemd-timesyncd is common. On AlmaLinux and Rocky Linux, chronyd is common. The command is written to allow either service to start cleanly.
Set a descriptive hostname on the VPS as root. Replace the example with your own staging hostname if needed:
hostnamectl set-hostname staging.example.com
hostnamectl statusNext, configure the firewall. Keep port 22 open so you do not lock yourself out. Add HTTP and HTTPS before reloading.
Ubuntu / Debian with UFW, on the VPS as root:
ufw allow OpenSSH
ufw allow 80/tcp
ufw allow 443/tcp
ufw enable
ufw status verboseAlmaLinux / Rocky Linux with firewalld, on the VPS as root:
systemctl enable --now firewalld
firewall-cmd --permanent --add-service=ssh
firewall-cmd --permanent --add-service=http
firewall-cmd --permanent --add-service=https
firewall-cmd --reload
firewall-cmd --list-allIf you use SELinux on AlmaLinux or Rocky Linux, confirm it is enforcing before you continue:
getenforceIf it returns Enforcing, leave it that way. This tutorial uses a standard web-root location and Nginx/PHP-FPM defaults that work with SELinux when file contexts are correct.
Install the database and create WordPress credentials
WordPress needs a database before installation. Use MySQL on Debian-family systems and MariaDB on AlmaLinux or Rocky Linux.
Ubuntu / Debian, on the VPS as root:
systemctl enable --now mysql
mysql_secure_installationAnswer the prompts to set a root password if required, remove anonymous users, disallow remote root login, remove the test database, and reload privilege tables. Then create the WordPress database and user:
mysql -u root -pAt the MySQL prompt, run:
CREATE DATABASE wordpress_staging DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
CREATE USER 'wpuser'@'localhost' IDENTIFIED BY 'ChangeThisLongRandomPassword';
GRANT ALL PRIVILEGES ON wordpress_staging.* TO 'wpuser'@'localhost';
FLUSH PRIVILEGES;
EXIT;AlmaLinux / Rocky Linux, on the VPS as root:
systemctl enable --now mariadb
mysql_secure_installationThen create the same database and user:
mysql -u root -pAt the MariaDB prompt, run the same SQL block shown above. The result should be a dedicated database that only WordPress uses.
Download WordPress, set ownership, and create wp-config.php
Work on the VPS as deploy from here onward. Create the site directory first:
sudo mkdir -p /var/www/wordpress-staging
sudo chown -R deploy:deploy /var/www/wordpress-stagingDownload and extract WordPress in the staging directory. The following commands run on the VPS as deploy:
cd /tmp
curl -O https://wordpress.org/latest.tar.gz
tar -xzf latest.tar.gz
rsync -a wordpress/ /var/www/wordpress-staging/Create the configuration file from the sample:
cd /var/www/wordpress-staging
cp wp-config-sample.php wp-config.phpEdit wp-config.php with your preferred editor and set the database name, username, and password. The relevant lines should look like this:
define( 'DB_NAME', 'wordpress_staging' );
define( 'DB_USER', 'wpuser' );
define( 'DB_PASSWORD', 'ChangeThisLongRandomPassword' );
define( 'DB_HOST', 'localhost' );Add authentication keys from WordPress.org to the same file. Save and exit the editor, then lock down the file:
sudo chown -R deploy:deploy /var/www/wordpress-staging
sudo find /var/www/wordpress-staging -type d -exec chmod 755 {} \;
sudo find /var/www/wordpress-staging -type f -exec chmod 644 {} \;
sudo chmod 640 /var/www/wordpress-staging/wp-config.phpCheck that the file permissions are correct. The config file should not be world-readable.
Configure Nginx and PHP-FPM
Now create the web server vhost. Use a staging server name, and keep the document root pointed at the WordPress directory.
Ubuntu / Debian, on the VPS as root or sudo user:
cat > /etc/nginx/sites-available/wordpress-staging.conf <<'EOF'
server {
listen 80;
server_name staging.example.com;
root /var/www/wordpress-staging;
index index.php index.html;
location / {
try_files $uri $uri/ /index.php?$args;
}
location ~ \.php$ {
include snippets/fastcgi-php.conf;
fastcgi_pass unix:/run/php/php-fpm.sock;
}
location ~* \.(js|css|png|jpg|jpeg|gif|ico|svg)$ {
expires max;
log_not_found off;
}
}
EOF
ln -s /etc/nginx/sites-available/wordpress-staging.conf /etc/nginx/sites-enabled/wordpress-staging.conf
nginx -tIf your Ubuntu or Debian release uses a versioned PHP-FPM socket such as /run/php/php8.4-fpm.sock, replace the socket path with the one shown by ls /run/php/. Validate before reload.
AlmaLinux / Rocky Linux, on the VPS as root or sudo user:
cat > /etc/nginx/conf.d/wordpress-staging.conf <<'EOF'
server {
listen 80;
server_name staging.example.com;
root /var/www/wordpress-staging;
index index.php index.html;
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;
}
}
EOF
nginx -tEnable and start the services:
systemctl enable --now php-fpm
systemctl enable --now nginx
systemctl reload nginxOn AlmaLinux and Rocky Linux, allow Nginx to connect to the database if SELinux blocks it:
setsebool -P httpd_can_network_connect_db onIf you later move the site to a different directory with SELinux enabled, restore contexts with restorecon -Rv /var/www/wordpress-staging.
Finish the web installer and issue TLS
Open the staging site in a browser at http://staging.example.com. Complete the WordPress installer with the site title, admin username, and a strong password. Confirm that you can log in at /wp-admin.
Once the site loads correctly over HTTP, issue a certificate. The exact command depends on your distribution and web server layout.
Ubuntu / Debian with Certbot and Nginx, on the VPS as root:
apt -y install certbot python3-certbot-nginx
certbot --nginx -d staging.example.comAlmaLinux / Rocky Linux, on the VPS as root:
dnf -y install certbot python3-certbot-nginx
certbot --nginx -d staging.example.comWhen prompted, choose the redirect option so HTTP sends visitors to HTTPS. Then test renewal safely:
certbot renew --dry-runYour browser should now load the site over HTTPS with a valid certificate.
Move staging changes to production
When testing is complete, promote the site by switching the DNS record from staging.example.com to www.example.com or by cloning the site into the production document root. For a clean rollout, update the WordPress site URLs in the database after the final hostname is chosen.
From the WordPress database on the VPS, run this only after you are certain about the final domain:
mysql -u root -pAt the prompt:
USE wordpress_staging;
UPDATE wp_options SET option_value='https://www.example.com' WHERE option_name IN ('siteurl','home');
EXIT;Then update the WordPress Address and Site Address from the admin dashboard if needed. After the DNS change, validate the live URL from your local computer:
curl -I https://www.example.comYou want a 200 or a redirect to the final destination, not a certificate or DNS error.
Final verification, logs, and rollback
Run the server-side checks on the VPS as root or sudo user:
systemctl status nginx --no-pager
systemctl status php-fpm --no-pager
systemctl status mysql --no-pager || systemctl status mariadb --no-pager
ss -tulpn | grep -E ':80|:443'
journalctl -u nginx -n 50 --no-pager
journalctl -u php-fpm -n 50 --no-pagerFor a browser-side smoke test, confirm the homepage, login page, and a sample post or page all load over HTTPS. If the site breaks after a change, roll back in this order: restore the previous database backup, restore the previous wp-config.php, restore the previous Nginx config, and reload only after nginx -t passes.
For site operators who want to test recovery procedures as part of the same workflow, link this tutorial with Backup Restore Testing on Linux Dedicated Servers and Backup Verification on Ubuntu 26.04 and AlmaLinux 10. If you are comparing where to place the site long term, How to Compare Dedicated Server Options in 2026 covers the hardware side.
Need a clean staging-to-production path on your own hardware? Start with a dedicated server from HostnExtra and build your WordPress workflow on storage, bandwidth, and root access you control.
FAQ
Can I use this workflow for WooCommerce?
Yes. Use the same staging process, but test checkout, payment gateway callbacks, email delivery, and cache settings before production.
Should staging be blocked from indexing?
Yes. Add noindex rules in WordPress or HTTP headers, and keep staging behind access control if it contains sensitive data.
What if my PHP-FPM socket name is different?
Check the active socket with ls /run/php/ on Ubuntu or Debian, or ls /run/php-fpm/ on AlmaLinux or Rocky Linux, then update the Nginx config and rerun nginx -t.
Do I need separate servers for staging and production?
Not always, but separate hosts reduce the chance that a staging change affects live traffic. A dedicated server makes that split easier to manage.

