Quick answer: Install Nginx, MariaDB and PHP-FPM, create a database for WordPress, extract WordPress to /var/www/wordpress, add an Nginx server block that passes .php requests to the PHP-FPM socket, then finish the install in your browser. Add a free SSL certificate with Certbot before you go live.

This guide is written for Ubuntu 24.04 LTS, which ships PHP 8.3 by default. The same steps work on Ubuntu 22.04 and on Debian, with only the PHP version number changing.

A note if you followed the old version of this guide: it used PHP 5, which reached end of life at the end of 2018 and has received no security patches since. If you are still running PHP 5 anywhere, that is the most urgent thing on your to-do list. The steps below replace it entirely.

Before you begin

  • A server running Ubuntu 24.04 or 22.04, with a user who has sudo rights.
  • A domain name pointed at the server’s IP address, if you intend to use SSL.
  • SSH access to the server.

Start by updating the system:

sudo apt update && sudo apt upgrade -y

Step 1: Install Nginx

sudo apt install nginx -y

Enable it so it starts automatically after a reboot, and start it now:

sudo systemctl enable nginx
sudo systemctl start nginx

If the firewall is active, allow web traffic through:

sudo ufw allow 'Nginx Full'

Visit your server’s IP address in a browser. The default Nginx welcome page confirms it is working.

Step 2: Install MariaDB and secure it

sudo apt install mariadb-server -y
sudo systemctl enable --now mariadb

Run the hardening script, which removes the test database, anonymous users and remote root login:

sudo mysql_secure_installation

Answer the prompts as follows:

Prompt Answer Why
Enter current password for root Press Enter None is set yet
Switch to unix_socket authentication Y More secure than a password for local root
Change the root password N (if you chose unix_socket) Not needed with socket auth
Remove anonymous users Y They allow unauthenticated access
Disallow root login remotely Y Root should only connect locally
Remove test database Y It is world-writable by default
Reload privilege tables Y Applies everything immediately

Step 3: Create the WordPress database

With unix_socket authentication, you log in as root without a password:

sudo mysql

Then create the database and a dedicated user. Replace the password with a strong one of your own:

CREATE DATABASE wpdb DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
CREATE USER 'wpuser'@'localhost' IDENTIFIED BY 'your_strong_password_here';
GRANT ALL PRIVILEGES ON wpdb.* TO 'wpuser'@'localhost';
FLUSH PRIVILEGES;
EXIT;

Using utf8mb4 matters. It is what lets WordPress store emoji and the full range of Unicode characters without mangling them.

Never let WordPress connect as the database root user. A dedicated account limited to one database means a compromised site cannot reach anything else on the server.

Step 4: Install PHP-FPM and the modules WordPress needs

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

On Ubuntu 24.04 this installs PHP 8.3. Confirm the version and that the service is running:

php -v
systemctl status php8.3-fpm

Note the version number, because you need it for the socket path in the Nginx configuration below.

Step 5: Download WordPress

cd /tmp
wget https://wordpress.org/latest.tar.gz
tar -xvzf latest.tar.gz
sudo mv wordpress /var/www/wordpress

Installing to /var/www/wordpress rather than /var/www/html keeps your site separate from the Nginx default, which makes hosting more than one site far tidier later.

Step 6: Set ownership and permissions

Get this right and a great many “WordPress cannot write to the directory” problems never happen.

sudo chown -R www-data:www-data /var/www/wordpress
sudo find /var/www/wordpress -type d -exec chmod 755 {} \;
sudo find /var/www/wordpress -type f -exec chmod 644 {} \;

Directories get 755 and files get 644. Applying 755 to everything, as older guides suggest, makes every file executable, which is unnecessary and a little reckless.

Step 7: Create the Nginx server block

Create a configuration file for your site:

sudo nano /etc/nginx/sites-available/wordpress

Paste the following, replacing example.com with your domain and checking the PHP version in the socket path:

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

    root /var/www/wordpress;
    index index.php index.html index.htm;

    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;
    }

    location = /favicon.ico { log_not_found off; access_log off; }
    location = /robots.txt { allow all; log_not_found off; access_log off; }
}

The try_files $uri $uri/ /index.php?$args; line is what makes WordPress permalinks work. Without it, every page except the homepage returns a 404.

Enable the site, remove the default, test the configuration and reload:

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

Always run nginx -t before reloading. It catches syntax errors while the old configuration is still serving traffic.

Step 8: Configure wp-config.php

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

Fill in the database details you created earlier:

define( 'DB_NAME', 'wpdb' );
define( 'DB_USER', 'wpuser' );
define( 'DB_PASSWORD', 'your_strong_password_here' );
define( 'DB_HOST', 'localhost' );

Then replace the authentication keys and salts. Visit the WordPress secret key generator, copy the block it produces, and paste it over the matching placeholder lines. Skipping this step leaves your sessions far easier to hijack.

Step 9: Finish the install in your browser

Go to your domain or server IP. The WordPress setup screen appears. Choose your site title, create an admin account with a strong password, and complete the installation.

Pick something other than admin for the username. Automated attacks try that first, every time.

Step 10: Add a free SSL certificate

Do not leave a WordPress login form running over plain HTTP.

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

Certbot obtains the certificate, edits your server block to serve HTTPS, and sets up automatic renewal. Confirm renewal works with:

sudo certbot renew --dry-run

Troubleshooting

Symptom Likely cause Fix
502 Bad Gateway Wrong PHP-FPM socket path Check the version with php -v and match the socket in the server block
Browser downloads the PHP file Nginx is not passing PHP to FPM Confirm the location ~ \.php$ block exists and reload Nginx
Homepage works, other pages 404 Missing try_files rule Add try_files $uri $uri/ /index.php?$args;
“Error establishing a database connection” Wrong credentials in wp-config.php Recheck the name, user and password, and that MariaDB is running
Cannot upload media or install plugins Ownership is wrong Run sudo chown -R www-data:www-data /var/www/wordpress
Upload size too small PHP defaults are conservative Raise upload_max_filesize and post_max_size in /etc/php/8.3/fpm/php.ini, then restart PHP-FPM
Certbot cannot verify the domain DNS not pointing at the server Confirm the A record resolves to your server IP and port 80 is open

Frequently asked questions

Nginx or Apache for WordPress?
Both work well. Nginx typically handles many simultaneous connections with less memory, which matters on small servers. Apache is more forgiving because of .htaccess support. On a modest VPS, Nginx is the better default.

MariaDB or MySQL?
MariaDB is a drop-in replacement and is what Ubuntu packages by default. WordPress cannot tell the difference.

Do I have to use PHP 8.3?
Use whatever your Ubuntu release ships, so long as it is still supported. Avoid anything below PHP 8.1, since older versions no longer receive security fixes.

How do I host a second site?
Create another directory under /var/www, add a second server block with its own server_name, and enable it. That is exactly why this guide avoids /var/www/html.

Should I still run apt-get?
Use apt. It is the modern front-end and the one Ubuntu recommends for interactive use.

Related guides