Host WordPress on a VPS the fast way

Install WordPress on your own server with nginx, PHP-FPM and MariaDB, get HTTPS from Let's Encrypt, and set up uploads, caching, updates and backups.

To host WordPress on a VPS, install nginx, PHP-FPM and MariaDB, create a database for WordPress, unpack it into a web directory, and add a free HTTPS certificate with Certbot. On a fresh Ubuntu 24.04 or Debian 12 server it takes about twenty minutes, and a server with 2 GB of memory runs a typical site comfortably.

nginx with PHP-FPM is the fast combination: nginx serves images, CSS and scripts itself and hands only the PHP to PHP-FPM. Commands below are run as root.

Point your domain at the server

Do this first, since DNS can take a few minutes and Certbot needs it. At your DNS provider, add A records for example.com and www.example.com with your server's IPv4 address, say 203.0.113.10. Add AAAA records for its IPv6 address once IPv6 works on the server.

Open the web ports:

bash
ufw allow 80/tcp
ufw allow 443/tcp

Install nginx, PHP and MariaDB

bash
apt update
apt install -y nginx mariadb-server php-fpm php-mysql php-curl php-gd php-intl php-mbstring php-xml php-zip php-imagick

That's the PHP your distribution ships: 8.3 on Ubuntu 24.04, 8.2 on Debian 12, 8.4 on Debian 13. All of them run current WordPress.

MariaDB's root account logs in through the Unix socket, so only root on the server can use it. There's no root password to set or lose.

Create the database

Make a password for WordPress's database user and keep it for a minute:

bash
openssl rand -base64 24

Then create the database and user, with that password in place of PASSWORD:

bash
mariadb <<'EOF'
CREATE DATABASE wordpress DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
CREATE USER 'wordpress'@'localhost' IDENTIFIED BY 'PASSWORD';
GRANT ALL PRIVILEGES ON wordpress.* TO 'wordpress'@'localhost';
EOF

Download WordPress

bash
cd /var/www
curl -fsSLO https://wordpress.org/latest.tar.gz
tar xzf latest.tar.gz
rm latest.tar.gz
chown -R www-data:www-data /var/www/wordpress

Owning the files as www-data lets WordPress install plugins and updates itself from the dashboard.

Configure nginx

Create /etc/nginx/sites-available/wordpress, with your domain:

nginx
server {
    listen 80;
    listen [::]:80;
    server_name example.com www.example.com;

    root /var/www/wordpress;
    index index.php;
    client_max_body_size 64M;

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

    location ~ \.php$ {
        include snippets/fastcgi-php.conf;
        fastcgi_pass unix:/run/php/php-fpm.sock;
    }

    location = /xmlrpc.php {
        deny all;
    }

    location ~ /\.(?!well-known) {
        deny all;
    }
}

/run/php/php-fpm.sock points at whichever PHP version is installed. If nginx complains it doesn't exist, ls /run/php/ shows the real name, like php8.3-fpm.sock.

Blocking xmlrpc.php stops a favourite target of password-guessing bots. Leave it open only if you use the Jetpack plugin or the old mobile apps.

Turn the site on and the default page off:

bash
ln -s /etc/nginx/sites-available/wordpress /etc/nginx/sites-enabled/
rm /etc/nginx/sites-enabled/default
nginx -t && systemctl reload nginx

Raise PHP's upload limit

PHP accepts 2 MB uploads by default, too small for photos and themes. Match the 64 MB nginx now allows:

bash
printf "upload_max_filesize = 64M\npost_max_size = 64M\nmemory_limit = 256M\n" > /etc/php/$(php -r 'echo PHP_MAJOR_VERSION.".".PHP_MINOR_VERSION;')/fpm/conf.d/99-wordpress.ini
systemctl restart "php*-fpm"

Get the HTTPS certificate

bash
apt install -y certbot python3-certbot-nginx
certbot --nginx -d example.com -d www.example.com

Certbot asks for an email address for expiry warnings, gets the certificate, and changes the nginx config to use it and redirect HTTP to HTTPS. It renews on its own. Serve a site with nginx and HTTPS has more detail and fixes for when it fails.

Run the installer straight away

Open https://example.com. WordPress asks for the database details:

  • Database name: wordpress
  • Username: wordpress
  • Password: the one you generated
  • Database host: localhost

Then pick the site title, an admin username that isn't admin, and a strong password. Do it now: until it's done, anyone who finds the address can run the installer and take over the site.

Make it fast

  • OPcache comes with PHP and is on by default. Nothing to do.
  • A page cache plugin (WP Super Cache, W3 Total Cache and others) serves most visitors a saved copy of the page instead of running PHP and the database every time. It's the biggest single speed-up for most sites.
  • An object cache with Redis helps busy sites and WooCommerce stores. Install redis-server and php-redis and a Redis object cache plugin.
  • Images: resize them before uploading. A 6 MB photo is slow on any server.

Keep it safe

  • WordPress installs minor core updates on its own. Update plugins and themes weekly, or turn on auto-updates for them in the dashboard.
  • Delete plugins and themes you don't use. Most WordPress break-ins come through an outdated plugin.
  • Keep the server patched with automatic security updates, and slow down login bots with fail2ban.

Back it up

A WordPress site is the database plus wp-content. Nightly, from root's crontab (crontab -e):

bash
0 3 * * * mariadb-dump --single-transaction wordpress | gzip > /root/wp-db-$(date +\%F).sql.gz && tar czf /root/wp-content-$(date +\%F).tgz -C /var/www/wordpress wp-content

Then copy them off the server. Backups you should run shows how, and how to prove a restore works.

When it goes wrong

  • "Error establishing a database connection": the details in /var/www/wordpress/wp-config.php don't match the database user. Check them with mariadb -u wordpress -p wordpress.
  • 502 Bad Gateway: nginx can't reach PHP-FPM. Check systemctl status "php*-fpm" and the socket path in the nginx config.
  • "The uploaded file exceeds the upload_max_filesize directive": the PHP limit above wasn't applied. Check with php-fpm8.3 -i | grep upload_max (use your version), and restart PHP-FPM.
  • WordPress asks for FTP details to install a plugin: the files aren't owned by www-data. Run the chown command again.

Doing it on VPSNine

The WordPress one-click app does everything up to the installer on the first boot: nginx, PHP-FPM, MariaDB, its own database and user, and the latest WordPress. Open your server's address, finish the five-minute install straight away, then point your domain at it and run Certbot.

It runs on any plan, Budget included, on Ubuntu or Debian. If you'd rather lay out the stack yourself, the LEMP stack app gives you nginx, PHP-FPM and MariaDB without WordPress. Moving an existing site? Move a site from shared hosting to a VPS covers that. The plans page has the specs.

Be first when orders open

Join the waitlist and we'll send you one email when VPSNine launches. Pick a plan if you already know which one you want, and we'll size the first servers around it.

  • One email, on launch day
  • Monthly, or a year up front in Bitcoin
  • 14-day money-back guarantee