How to host a WordPress site on your own VPS

WordPress runs a large share of the web, and a VPS lets you host it with full control and without paying for a managed plan. It is a manageable project if you take it in stages: a web server, PHP, a database, WordPress itself and HTTPS. This guide uses nginx, PHP-FPM and MariaDB, a combination often called a LEMP stack, on Ubuntu.

You are taking on the work of keeping it updated and backed up. If you would rather not, a managed WordPress plan is a fair choice. If you want the control, read on.

Before you start

Step 1: install the software

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

Ubuntu installs the current PHP version for your release. Find the exact version, which you need for the socket path later:

ls /run/php/

You will see a file such as php8.3-fpm.sock.

Step 2: create the database

Secure MariaDB first, following How to install and secure MariaDB on Ubuntu. Then:

sudo mysql
CREATE DATABASE wordpress CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
CREATE USER 'wpuser'@'localhost' IDENTIFIED BY 'a-long-random-password';
GRANT ALL PRIVILEGES ON wordpress.* TO 'wpuser'@'localhost';
FLUSH PRIVILEGES;
EXIT;

Step 3: download WordPress

cd /tmp
curl -LO https://wordpress.org/latest.tar.gz
tar -xzf latest.tar.gz
sudo mkdir -p /var/www/mysite
sudo cp -a wordpress/. /var/www/mysite/
sudo chown -R www-data:www-data /var/www/mysite

Always download from the official WordPress site.

Step 4: configure WordPress

Copy the sample config and edit it:

cd /var/www/mysite
sudo cp wp-config-sample.php wp-config.php
sudo nano wp-config.php

Set DB_NAME, DB_USER and DB_PASSWORD to the values from step 2, and DB_HOST to localhost. Replace the placeholder security keys with fresh random ones. WordPress offers a page that generates them, at https://api.wordpress.org/secret-key/1.1/salt/. Then restrict the file, since it holds your database password:

sudo chmod 640 wp-config.php

Step 5: configure nginx

Create /etc/nginx/sites-available/mysite:

server {
    listen 80;
    listen [::]:80;
    server_name mydomain.net www.mydomain.net;
    root /var/www/mysite;
    index index.php;

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

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

    location ~ /\.ht {
        deny all;
    }

    client_max_body_size 64M;
}

Use the socket name from step 1, and your own domain. The client_max_body_size line allows larger uploads, such as images. Enable it, test and reload:

sudo ln -s /etc/nginx/sites-available/mysite /etc/nginx/sites-enabled/
sudo nginx -t
sudo systemctl reload nginx

More on this layout is in How to host several websites on one VPS with nginx server blocks.

Step 6: add HTTPS

sudo certbot --nginx -d mydomain.net -d www.mydomain.net

See Set up an SSL certificate (HTTPS). Then visit your domain and complete the WordPress installer in the browser, choosing the admin username and a strong password.

Step 7: keep it secure and healthy

WordPress is a popular target, so attention to the basics matters:

  • Update everything: WordPress, themes and plugins. Most hacked sites run outdated plugins. Turn on automatic updates for minor releases, and check weekly for the rest.
  • Remove what you do not use. Delete unused themes and plugins instead of just deactivating them.
  • Use strong, unique passwords and two-factor authentication for admin accounts.
  • Limit login attempts with a plugin, or block repeat offenders with Fail2ban.
  • Install plugins only from trusted sources.
  • Keep file permissions tight. Files should be readable by the web server, and only what must be writable, such as wp-content/uploads, should be.
  • Back up the files and the database on a schedule, and test restores. See How to back up your VPS with rsync and The 3-2-1 backup rule.

Speed

A few simple things help a lot: enable PHP's opcache, which is on by default in recent versions, use a caching plugin, compress images before uploading and keep plugins few. If the server runs out of memory, see the section on swap in How to add swap space to your VPS.

Troubleshooting

ProblemLikely cause
"Error establishing a database connection"Wrong credentials in wp-config.php, or MariaDB stopped
502 Bad GatewayPHP-FPM not running, or the socket path is wrong. See How to fix nginx 502 and 504 errors
403 or 404 on pagesPermalinks need the try_files line above
Cannot upload filesFolder ownership, or client_max_body_size too small
White screenA plugin error. Check the nginx and PHP logs

Still stuck? Open a ticket on Discord - run /ticket in any channel, pick a department, and include your Server ID or Invoice ID so we can jump straight in.