GuidesGuide

WordPress Hosting on a VPS - Complete Ubuntu 24.04 Guide

Hosting WordPress on a VPS makes sense when you want predictable performance and full control: for a typical site, 2 vCPUs and 2-4 GB of RAM running nginx + PHP-FPM + MariaDB + Redis, with HTTPS, off-server backups and controlled updates, is all you need. You can build it by hand (this guide has the exact Ubuntu 24.04 commands) or let a control panel do it for you. The real work isn't the install, it's the maintenance in the months that follow.

VPS, shared hosting or managed WordPress?

Shared hosting Managed WordPress VPS
Resources shared with other customers dedicated, within plan limits dedicated, you choose them
Control low medium (banned plugins, no root) full
Maintenance provider provider you (or your panel)
Cost for many sites grows per site grows per site flat per server

If you run one small site and never want to think about servers, a good managed WordPress host is still the easiest option. A VPS pays off when you have several sites, a WooCommerce store that crawls on shared hosting, or clients to host: you pay per server, not per site.

How big should the VPS be?

Starting points, to be checked against your real traffic:

Scenario vCPU RAM Disk
1-3 blogs or brochure sites 1-2 2 GB 25-40 GB NVMe
5-15 sites, small WooCommerce store 2 4 GB 50-80 GB
Busy WooCommerce, or 20+ sites 4 8 GB 100 GB+

With page caching, anonymous visitors barely touch the CPU. What costs you is logged-in users, cart, checkout and wp-admin, none of which can be page-cached. If you also host email with spam and virus filtering, add 1-2 GB of RAM.

  • nginx: very efficient at serving static files and cached pages. It ignores .htaccess files, so rules live in the site's server block.
  • PHP-FPM 8.3: the version shipped with Ubuntu 24.04 and the one recommended in the official WordPress requirements. A separate pool per site, running as its own system user, keeps sites isolated.
  • MariaDB 10.11: also WordPress's recommended minimum.
  • Redis: persistent object cache that cuts database queries.
  • OPcache: keeps compiled PHP in memory.

Manual setup on Ubuntu 24.04

The examples use the domain example.com and a site system user called example. Start from an up-to-date VPS (sudo apt update && sudo apt -y full-upgrade).

1. Packages

sudo apt install -y nginx mariadb-server redis-server unzip \
php8.3-fpm php8.3-cli php8.3-mysql php8.3-curl php8.3-gd php8.3-mbstring \
php8.3-xml php8.3-zip php8.3-intl php8.3-bcmath php8.3-opcache \
php-imagick php-redis certbot python3-certbot-nginx

2. Site user and a dedicated PHP-FPM pool

sudo useradd -m -d /var/www/example.com -s /usr/sbin/nologin example
sudo chmod 750 /var/www/example.com
sudo usermod -aG example www-data
sudo -u example mkdir /var/www/example.com/public_html

Create /etc/php/8.3/fpm/pool.d/example.conf:

[example]
user = example
group = example
listen = /run/php/example.sock
listen.owner = www-data
listen.group = www-data
pm = ondemand
pm.max_children = 10
pm.process_idle_timeout = 30s
php_admin_value[memory_limit] = 256M
php_admin_value[upload_max_filesize] = 64M
php_admin_value[post_max_size] = 64M
sudo systemctl restart php8.3-fpm

3. Database

On Ubuntu, MariaDB's root user authenticates over the Unix socket, no password needed. Create a dedicated database and user:

sudo mariadb <<'SQL'
CREATE DATABASE wp_example CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
CREATE USER 'wp_example'@'localhost' IDENTIFIED BY 'a-long-random-password';
GRANT ALL PRIVILEGES ON wp_example.* TO 'wp_example'@'localhost';
FLUSH PRIVILEGES;
SQL

4. nginx configuration

Create /etc/nginx/conf.d/wp-login-limit.conf with a single line to rate-limit logins:

limit_req_zone $binary_remote_addr zone=wplogin:10m rate=10r/m;

Then /etc/nginx/sites-available/example.com:

server {
listen 80;
listen [::]:80;
server_name example.com www.example.com;
root /var/www/example.com/public_html;
index index.php;
client_max_body_size 64m;
location = /xmlrpc.php { deny all; }
location ~* /wp-content/uploads/.*\.php$ { deny all; }
location ~ /\.(?!well-known) { deny all; }
location = /wp-login.php {
limit_req zone=wplogin burst=5 nodelay;
include snippets/fastcgi-php.conf;
fastcgi_pass unix:/run/php/example.sock;
}
location / { try_files $uri $uri/ /index.php?$args; }
location ~ \.php$ {
include snippets/fastcgi-php.conf;
fastcgi_pass unix:/run/php/example.sock;
}
}

The deny rules sit above \.php$ because nginx uses the first matching regex. Enable the site and request a certificate (the domain must already point at the VPS):

sudo ln -s /etc/nginx/sites-available/example.com /etc/nginx/sites-enabled/
sudo nginx -t && sudo systemctl reload nginx
sudo certbot --nginx -d example.com -d www.example.com

Certbot adds the HTTPS block, the HTTP redirect and automatic renewal.

5. WordPress with WP-CLI

curl -O https://raw.githubusercontent.com/wp-cli/builds/gh-pages/phar/wp-cli.phar
chmod +x wp-cli.phar
sudo mv wp-cli.phar /usr/local/bin/wp
W="sudo -u example wp --path=/var/www/example.com/public_html"
$W core download
$W config create --dbname=wp_example --dbuser=wp_example --prompt=dbpass
$W core install --url=https://example.com --title="My Site" \
--admin_user=jane --admin_email=jane@example.com

--prompt=dbpass keeps the database password out of your shell history, and without --admin_password WP-CLI generates one and prints it once. Don't use admin as the username: it's the first one bots try.

6. Redis, WP-Cron and hardening

Cap Redis memory in /etc/redis/redis.conf (maxmemory 128mb and maxmemory-policy allkeys-lru), restart it with sudo systemctl restart redis-server, then:

$W config set WP_REDIS_PREFIX example:
$W plugin install redis-cache --activate
$W redis enable
$W config set DISALLOW_FILE_EDIT true --raw
$W config set DISABLE_WP_CRON true --raw
echo '*/5 * * * * /usr/local/bin/wp --path=/var/www/example.com/public_html cron event run --due-now --quiet' | sudo crontab -u example -

The prefix stops several sites sharing one Redis from colliding. Running WP-Cron from system cron means scheduled events fire even with no traffic.

Security

  • Firewall: open only SSH, 80 and 443 (sudo ufw allow OpenSSH, sudo ufw allow 'Nginx Full', sudo ufw enable).
  • Key-based SSH with password logins disabled.
  • fail2ban against brute force on SSH and wp-login.php (sudo apt install -y fail2ban: the SSH jail is on by default on Ubuntu, the WordPress one you add yourself).
  • Automatic security updates: unattended-upgrades ships enabled on Ubuntu; check with systemctl status unattended-upgrades.
  • Isolation: one system user and one PHP pool per site, as above.
  • Integrity: $W core verify-checksums compares core files against the official ones.

The full checklist is in How to secure a VPS for web hosting.

Backups

Rule of thumb: one copy off the server, encrypted, automated and tested with a real restore now and then. With restic (in Ubuntu's repositories) and any S3 bucket:

sudo apt install -y restic
sudo -u example mkdir -p /var/www/example.com/backup
$W db export /var/www/example.com/backup/db.sql
sudo RESTIC_REPOSITORY=s3:https://s3.us-east-1.amazonaws.com/my-bucket/wp \
RESTIC_PASSWORD_FILE=/root/.restic-pass \
AWS_ACCESS_KEY_ID=... AWS_SECRET_ACCESS_KEY=... \
restic backup /var/www/example.com

Run restic init once with the same variables first; afterwards restic forget --keep-daily 7 --keep-weekly 4 --prune trims old snapshots. More detail in Backing up websites to S3.

Updates without surprises

Keeping WordPress, plugins and themes current is your first line of defense, and also the most common way sites break. A safe routine:

  1. back up files and database right before;
  2. $W core update, $W core update-db, $W plugin update --all, $W theme update --all;
  3. $W core verify-checksums;
  4. check the homepage returns a 200 (curl -sI https://example.com);
  5. if anything's off, restore from the backup.

For bigger changes (a new theme, a WooCommerce upgrade) test on a staging copy first.

By hand or with a panel?

By hand With a panel
Cost no license license (or free within limits)
Time per new site 30-60 minutes a few minutes
Updates with rollback you script it depends on the panel
Risk of config mistakes yours reduced
Best for 1-2 sites, terminal lovers many sites, clients, agencies

Building it by hand is the best way to learn the stack. With many sites, though, repeating every step and remembering the backups becomes the real cost.

WordPress on a VPS with Koapanel

Koapanel automates the stack above on Ubuntu 24.04. Its WordPress section includes:

  • one-click install: dedicated database, wp-config.php with fresh keys, permalinks, WP-Cron on system cron and a final health check. Every command runs as the site's system user, never as root;
  • three cache layers, preconfigured: nginx page cache (skipping logged-in users, cart, checkout and admin, WooCommerce included), a private Redis per site on a local socket with no network port, and OPcache. The panel measures homepage response time with and without cache;
  • safe updates with automatic rollback: backup, update, verification against official checksums and a homepage check; if any step fails, files and database roll back on their own and you get an email. Nightly auto-updates follow the same procedure;
  • toggle-based hardening: login rate limiting, fail2ban on login and XML-RPC, XML-RPC closed, PHP blocked in uploads, file editor disabled, sensitive files hidden, nightly integrity checks;
  • staging copy, password-protected and not indexed, publishable to production (files, database or both);
  • tools: password-less wp-admin login via a 60-second single-use link, search and replace that handles serialized data, WP-CLI in the browser, debug and maintenance modes;
  • import of an existing WordPress site from a file archive and SQL dump.

Backups go to S3 or local disk via restic (Backup and restore). Limits worth knowing: no Apache or .htaccess (Apache rules written by caching or security plugins aren't needed, since nginx already handles caching), no WordPress multisite, and SFTP instead of classic FTP.

FAQ

How much RAM does WordPress need on a VPS?

For one or a few sites, 2 GB with Redis and page caching is enough. For WooCommerce or more than ten sites, start at 4 GB.

nginx or Apache for WordPress?

Both work well. nginx with PHP-FPM uses less memory and serves cached pages faster; Apache's advantage is .htaccess support, handy when a plugin depends on it.

Do I really need Redis?

On sites with logged-in users, WooCommerce or lots of plugins it cuts database load noticeably. On a page-cached blog the gain is smaller, but it costs little memory.

Can I move an existing WordPress site to the VPS?

Yes: copy the files, export and import the database, update wp-config.php and rewrite the URL with wp search-replace. Koapanel does this through its Import feature, or migrates whole accounts from cPanel and Plesk (migration).

Does Koapanel support WordPress multisite?

No, it currently manages single-site installs.

Try WordPress on Koapanel

Want the stack from this guide ready to go? Install Koapanel for free on an Ubuntu 24.04 VPS (up to 3 sites for personal use) with the installation guide, or explore the WordPress section in the public demo (user admin, password demo-admin-2026).

Try Koapanel on your server

One command on Ubuntu 24.04, free up to 3 sites. Are you a provider or an agency? Let's talk wholesale pricing and migrations.

More guides