1. Blog
  2. Manuals

Install LEMP (Nginx, MySQL, PHP) on Ubuntu 24.04

Install LEMP (Nginx, MySQL, PHP) on Ubuntu 24.04

LEMP is the Linux, Nginx, MySQL and PHP stack behind WordPress, Laravel and most other PHP applications. This guide is written for Ubuntu 24.04 LTS and also works on 22.04 and 26.04: only the PHP version number differs.

What you need

  • a VPS running Ubuntu with SSH access;
  • a user with sudo rights;
  • a domain with an A record pointing to the server’s IP address (for SSL).

Update the system:

sudo apt update && sudo apt upgrade -y

Step 1. Nginx

sudo apt install -y nginx

If UFW is enabled, allow HTTP and HTTPS:

sudo ufw allow 'Nginx Full'

Open http://your-server-ip in a browser — you should see the “Welcome to nginx” page.

Step 2. MySQL

sudo apt install -y mysql-server

Run the basic hardening script. It removes anonymous users and the test database and disables remote root login:

sudo mysql_secure_installation

On Ubuntu the root user logs in to MySQL without a password, through sudo. Create a database and a dedicated user for the site:

sudo mysql
CREATE DATABASE site_db CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
CREATE USER 'site_user'@'localhost' IDENTIFIED BY 'a_strong_password';
GRANT ALL PRIVILEGES ON site_db.* TO 'site_user'@'localhost';
FLUSH PRIVILEGES;
EXIT;

Step 3. PHP

Nginx does not run PHP itself; it hands requests to the PHP-FPM service:

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

Find the installed version and the socket name — you need them in the next step:

php -v
ls /run/php/

On Ubuntu 24.04 that is PHP 8.3 and the php8.3-fpm.sock socket.

Step 4. Configure the site

Create the site directory:

sudo mkdir -p /var/www/example.com
sudo chown -R $USER:www-data /var/www/example.com

Create the configuration:

sudo nano /etc/nginx/sites-available/example.com
server {
    listen 80;
    listen [::]:80;
    server_name example.com www.example.com;

    root /var/www/example.com;
    index index.php index.html;

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

Enable the site, test the configuration and reload it:

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

The configuration is explained in detail in the Nginx virtual host guide.

Step 5. Test PHP

echo "<?php phpinfo();" > /var/www/example.com/info.php

Open http://example.com/info.php — a page with PHP settings appears.

Step 6. Test the database connection

Create /var/www/example.com/db.php:

<?php
$db = new mysqli('localhost', 'site_user', 'a_strong_password', 'site_db');
echo $db->connect_error ? 'Error: ' . $db->connect_error : 'MySQL connection works';

Open http://example.com/db.php, confirm the connection works, and delete the file.

Step 7. SSL certificate

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

Certbot obtains a Let’s Encrypt certificate and sets up HTTPS and the HTTP redirect. Renewal is automatic.

Basic PHP tuning

The settings are in /etc/php/8.3/fpm/php.ini. Most sites benefit from higher upload limits:

upload_max_filesize = 64M
post_max_size = 64M
memory_limit = 256M

For Nginx to accept such files, add client_max_body_size 64M; to the server block. Then restart the services:

sudo systemctl restart php8.3-fpm
sudo systemctl reload nginx

If something does not work

  • 502 Bad Gateway — the Nginx configuration points to the wrong PHP-FPM socket, or the service is not running: systemctl status php8.3-fpm.
  • The browser downloads the PHP file — the site configuration has no location ~ \.php$ block.
  • Access denied for user — check the user name, password and database privileges.
  • Logs — /var/log/nginx/error.log and journalctl -u php8.3-fpm.