MHOSTMHOST

How to Install WordPress on a VPS: Nginx, PHP, MySQL

WordPress runs faster on a VPS than on shared hosting: the server's resources are reserved for you, and you can tune PHP, the database and caching for your site. Nobody limits the number of sites, plugins or load.

This guide installs WordPress on a LEMP stack: Linux, Nginx, MySQL and PHP. It takes 20–30 minutes. You'll end up with a site on HTTPS with upload limits configured, basic protection and static file caching.

Requirements:

  • A VPS running Ubuntu 22.04, 24.04 or 26.04. 1 GB RAM is enough for a small site; for a WooCommerce store, get 2 GB or more.
  • A user with sudo and a configured firewall. If the server is new, complete the initial VPS setup first.
  • A domain whose A records (for example.com and www) point to the server's IP.

Replace example.com with your domain in every command.

Step 1. Install Nginx, MySQL and PHP

One command installs the web server, the database, PHP and the modules WordPress needs:

sudo apt update

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

Open the web ports in the firewall:

sudo ufw allow 'Nginx Full'

Find out which PHP version was installed — you'll need it in the Nginx config:

ls /run/php/

The output includes a file like php8.3-fpm.sock. The number depends on your Ubuntu version: 8.1 on 22.04, 8.3 on 24.04. The rest of this guide uses 8.3; substitute your own version.

You can install MariaDB (mariadb-server) instead of MySQL: WordPress works with both, and the commands below are the same.

Step 2. Create the Database

WordPress stores posts, pages and settings in a database. We'll create a separate database and a user that has access only to it.

First generate a password and save it:

openssl rand -base64 24

Open the MySQL console:

sudo mysql

Run the commands one at a time, using your own password:

CREATE DATABASE wordpress DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;

CREATE USER 'wpuser'@'localhost' IDENTIFIED BY 'YOUR_PASSWORD';

GRANT ALL PRIVILEGES ON wordpress.* TO 'wpuser'@'localhost';

FLUSH PRIVILEGES;

EXIT;

Remember three values: the database name wordpress, the user wpuser and the password. You'll need them in step 6.

On Ubuntu, the database listens only on localhost by default and isn't reachable from the internet. Don't open port 3306 in the firewall.

Step 3. Download WordPress

Download the latest version from the official site and unpack it into the site folder:

cd /tmp

curl -LO https://wordpress.org/latest.tar.gz

tar xzf latest.tar.gz

sudo mkdir -p /var/www/example.com

sudo cp -a /tmp/wordpress/. /var/www/example.com/

Need another language? You pick it on the first screen of the browser installer; there's no separate archive to download.

Hand the files over to www-data, the user Nginx and PHP run as:

sudo chown -R www-data:www-data /var/www/example.com

Without this, WordPress can't upload images, install plugins or update itself, and will ask for FTP credentials.

Step 4. Configure Nginx

Create the site config:

sudo nano /etc/nginx/sites-available/example.com

Paste the contents. Replace the domain and the PHP version in the fastcgi_pass line:

server {

listen 80;

server_name example.com www.example.com;

root /var/www/example.com;

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/php8.3-fpm.sock;

}

location ~* \.(css|js|jpg|jpeg|png|gif|webp|svg|ico|woff2)$ {

expires 30d;

}

location = /xmlrpc.php {

deny all;

}

}

What the key lines do:

  • try_files ... /index.php?$args sends all requests to WordPress. Without it, pretty links like /blog/my-post/ return a 404.
  • fastcgi_pass hands PHP files to PHP-FPM for processing.
  • client_max_body_size 64m allows uploads up to 64 MB: themes, plugins, video.
  • expires 30d makes browsers cache images, styles and scripts for 30 days, so repeat visits load faster.
  • location = /xmlrpc.php closes a legacy interface bots use to guess passwords. Remove this block only if you use the WordPress mobile app or the Jetpack plugin.

Enable the site, check the config and apply the changes:

sudo ln -s /etc/nginx/sites-available/example.com /etc/nginx/sites-enabled/

sudo nginx -t && sudo systemctl reload nginx

Step 5. Enable HTTPS

Get a free Let's Encrypt certificate before installing WordPress: the site will then store its address with https:// from the start, and you won't have to change it in the settings later.

sudo apt install -y certbot python3-certbot-nginx

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

Certbot adds the SSL settings to your config and turns on the HTTPS redirect and auto-renewal. For details and how to check auto-renewal, see how to install a Let's Encrypt SSL certificate on Nginx.

Step 6. Finish the Install in Your Browser

Open https://example.com. The WordPress installer appears:

  1. Choose the language for the site and admin area.
  2. Enter the database details from step 2: database name wordpress, user wpuser, your password, host localhost. Change the table prefix from the default wp_ to your own, such as s7k_: this gets in the way of common automated attacks.
  3. Create the administrator. Don't call it admin: bots try that login first. Use the password WordPress suggests and save it in a password manager.
  4. Log in to the admin area at https://example.com/wp-admin/.

After logging in, open Settings → Permalinks and choose "Post name". Links like /my-post-title/ are better for SEO than /?p=123.

Step 7. Set PHP Limits and the Scheduler

PHP limits. By default, PHP accepts files of up to 2 MB — not enough even for a phone photo. Create a settings file (use your own PHP version):

printf '%s\n' 'upload_max_filesize = 64M' 'post_max_size = 64M' 'memory_limit = 256M' 'max_execution_time = 300' | sudo tee /etc/php/8.3/fpm/conf.d/99-wordpress.ini

sudo systemctl restart php8.3-fpm

Check in the admin area: Media → Add New should show a maximum upload size of 64 MB.

Task scheduler. WordPress runs background tasks (scheduled posts, update checks, mailings) only when someone opens the site. On a low-traffic site tasks run late; on a busy one they slow pages down. Running them from the system cron is more reliable.

Open the WordPress config file:

sudo nano /var/www/example.com/wp-config.php

Add this line above the comment /* That's all, stop editing! */:

define('DISABLE_WP_CRON', true);

Open the www-data user's cron:

sudo crontab -u www-data -e

Add a run every 5 minutes:

*/5 * * * * php /var/www/example.com/wp-cron.php > /dev/null 2>&1

How to Secure WordPress

WordPress is the most popular CMS, so it's attacked the most. Nearly all break-ins happen through outdated plugins and weak passwords.

  • Update everything. Turn on auto-updates for plugins and themes in the admin area. Delete plugins and themes you don't use: a deactivated plugin can still be exploited.
  • Install plugins only from the official directory. "Free" copies of paid themes and plugins from pirate sites almost always contain malicious code.
  • Turn on two-factor authentication for administrators with a plugin.
  • Disable the file editor in the admin area. If an attacker gets into the admin area, they can't write their code into your theme. Add this line to wp-config.php: define('DISALLOW_FILE_EDIT', true);
  • Limit password guessing. Install a login-attempt limiter plugin or put Cloudflare in front with a rule for /wp-login.php. See how in how to protect a VPS from DDoS attacks.
  • Make backups. You need two things: the database and the wp-content folder with images, themes and plugins. Keep copies off the server.

Dump the database with one command:

sudo mysqldump wordpress | gzip > ~/wordpress-$(date +%F).sql.gz

Archive the site files:

sudo tar -czf ~/wp-content-$(date +%F).tar.gz -C /var/www/example.com wp-content

How to Speed Up WordPress

  • Install a page caching plugin. This has the biggest effect: a ready-made page is served without running PHP or querying the database.
  • Check OPcache. It caches compiled PHP code and is usually already on. Check with php -m | grep -i opcache.
  • Add a Redis object cache for stores and sites with many database queries: sudo apt install -y redis-server php-redis, then the Redis Object Cache plugin.
  • Compress images. Images are the heaviest part of a page. Upload them as WebP and no wider than your design needs.
  • Watch the number of plugins. Every plugin adds code that runs on every page.

Common Errors

  • 502 Bad Gateway. Nginx can't connect to PHP. Most often fastcgi_pass points to the wrong PHP version. Compare it with the output of ls /run/php/ and check the service: sudo systemctl status php8.3-fpm.
  • "Error establishing a database connection". Wrong database name, user or password in wp-config.php, or MySQL isn't running: sudo systemctl status mysql. On servers with 1 GB RAM, the system may kill the database when memory runs out — add swap.
  • Post pages return 404 while the home page works. The Nginx config is missing the line try_files $uri $uri/ /index.php?$args;.
  • 413 Request Entity Too Large when uploading a file. Raise client_max_body_size in Nginx and the PHP limits from step 7.
  • WordPress asks for FTP credentials when installing a plugin. The site files belong to the wrong user. Run sudo chown -R www-data:www-data /var/www/example.com again.
  • White screen. A PHP error, usually caused by a plugin or lack of memory. The cause is in the log: sudo tail -n 50 /var/log/nginx/error.log.
  • The site loads without styles or the browser reports mixed content. WordPress was installed over HTTP and HTTPS was enabled later. Change both addresses in Settings → General to https://.

Checklist

FAQ

What VPS do I need for WordPress? A blog or company site runs fine on 1 vCPU and 1 GB RAM. For WooCommerce or a site with thousands of daily visitors, get 2 vCPU and 2–4 GB RAM.

Do I need a control panel? No. Everything in this guide is done in the terminal, and you manage the site from the WordPress admin area. A panel is handy if you have many sites and don't want to edit configs by hand.

Can I host several sites on one VPS? Yes. Repeat steps 2–6 for each site: its own database, its own folder in /var/www and its own Nginx config.

Nginx or Apache for WordPress? Both work. Nginx uses less memory and serves static files faster, so it suits small VPS plans better. Apache understands .htaccess files, which some plugins rely on; with Nginx, those rules go in the config.

How do I move a site from shared hosting? Prepare the server with steps 1–5, then move the wp-content folder and a database dump, or use a migration plugin. Switch the domain to the new IP last, after you've checked the site on the new server.