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

VPS & Servers

0 people found this article helpful

Install Nginx, MySQL (or MariaDB) and PHP-FPM with apt, then add an Nginx server block that passes .php files to PHP-FPM.

Good to know: the commands are for Ubuntu 24.04 LTS, which comes with PHP 8.3, MySQL 8.0 and MariaDB 10.11. Ubuntu 26.04 LTS ships PHP 8.5, MySQL 8.4 and MariaDB 11.8: the steps are the same, but write 8.5 wherever this article says 8.3. Replace example.com with your domain and 203.0.113.10 with your server's IP address.

LEMP stands for Linux, Nginx ("engine-x"), MySQL and PHP. Connect to the server as a user with sudo rights (see Connect to your server with SSH). On a new server, do the basic security steps first: Secure a new Linux server: first 10 steps.

1. Install Nginx

sudo apt update
sudo apt install nginx

Open the web ports in the firewall (if UFW is on, see Set up a firewall with UFW on Ubuntu):

sudo ufw allow 'Nginx Full'

Open http://203.0.113.10 in your browser. You should see Welcome to nginx!

2. Install MySQL or MariaDB

Install one of the two, not both. Most PHP apps work with either.

sudo apt install mysql-server

or

sudo apt install mariadb-server

Check that it runs: sudo systemctl status mysql (MariaDB: sudo systemctl status mariadb) should show active (running). On Ubuntu, the database's root user logs in through the system's root account, without a password. Open the database console:

sudo mysql

Create a database and a user for your website (choose your own names and a strong password):

CREATE DATABASE example_db;
CREATE USER 'example_user'@'localhost' IDENTIFIED BY 'a-long-random-password';
GRANT ALL PRIVILEGES ON example_db.* TO 'example_user'@'localhost';
EXIT;

The database only listens on the server itself, which is what you want. Your website connects to localhost with this user.

3. Install PHP-FPM

Nginx doesn't run PHP itself: it hands PHP files to PHP-FPM. Install it with the MySQL extension:

sudo apt install php8.3-fpm php8.3-mysql

Most apps (WordPress, for example) also need a few common extensions:

sudo apt install php8.3-curl php8.3-gd php8.3-mbstring php8.3-xml php8.3-zip php8.3-intl

Check that PHP-FPM runs and find its socket, which Nginx needs in the next step:

sudo systemctl status php8.3-fpm
ls /run/php/

The list contains php8.3-fpm.sock.

4. Create the website in Nginx

  1. Create the website's folder and make your user its owner:

    sudo mkdir -p /var/www/example.com
    sudo chown -R $USER:$USER /var/www/example.com
  2. Create the server block:

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

    Paste this, change the domain, then save with Ctrl+O, Enter, and close with Ctrl+X:

    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/ =404;
        }
    
        location ~ \.php$ {
            include snippets/fastcgi-php.conf;
            fastcgi_pass unix:/run/php/php8.3-fpm.sock;
        }
    
        location ~ /\.ht {
            deny all;
        }
    }
  3. Turn the site on, test the configuration and reload Nginx:

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

    nginx -t must say syntax is ok and test is successful. If this is the only site on the server, you can switch off the welcome page with sudo unlink /etc/nginx/sites-enabled/default (then test and reload again).

5. Test PHP

Create a test file:

echo '<?php phpinfo();' | sudo tee /var/www/example.com/info.php

Open http://example.com/info.php (or use the server's IP address if the domain doesn't point to the server yet and this is the only site). You should see the PHP information page with Server API: FPM/FastCGI and a mysqli section. Then delete the file, because it shows details attackers like to know:

sudo rm /var/www/example.com/info.php

6. Next steps

  • Add free HTTPS: Install a free SSL certificate with Certbot.
  • For WordPress and other apps with pretty links, change the line in location / to try_files $uri $uri/ /index.php?$args; and reload Nginx.
  • Apps that save uploads or updates need write access for PHP, which runs as the user www-data. Give it only the folders that need it, for example sudo chown -R www-data:www-data /var/www/example.com/wp-content.
  • PHP settings are in /etc/php/8.3/fpm/php.ini. After a change, run sudo systemctl restart php8.3-fpm.
  • Want phpMyAdmin? See Install phpMyAdmin on Ubuntu.

Common problems

502 Bad Gateway

Nginx can't reach PHP-FPM. Check that it runs (sudo systemctl status php8.3-fpm) and that the socket in fastcgi_pass matches the file in /run/php/. The error log /var/log/nginx/error.log shows the details.

The browser downloads the .php file instead of showing the page

The location ~ \.php$ block is missing or Nginx wasn't reloaded. Check the server block, run sudo nginx -t and sudo systemctl reload nginx, and clear your browser cache.

413 Request Entity Too Large when uploading

Nginx allows uploads of 1 MB by default. Add client_max_body_size 64M; to the server block, and raise upload_max_filesize and post_max_size in php.ini. Reload Nginx and restart PHP-FPM.

You still see the Welcome to nginx page

Your domain's request lands in the default site. Check that server_name contains the exact domain you open, that the link in sites-enabled exists, and reload Nginx.

Access denied for user when the app connects to the database

Check the database name, username and password in the app's settings, and that the host is localhost. Log in with sudo mysql and run the GRANT line again if needed.

Related articles

Still stuck? Open a support ticket and we'll help.


Was this answer helpful?

2FA 301 redirect 3D Secure 404 page 500 error 550 error A record accept quote access log account credit account details account password Account Preferences account security add funds addon domain address importer affiliate program AI assistant AlmaLinux 9 Android email Apache Apache virtual host API token Apple Mail Ask AI auth code authenticator app auto-renew automatic payment automatic updates autoresponder AutoSSL bandwidth billing address billing contact billing section block editor block IP bounce bounce message BoxTrapper build a WordPress website bulk email accounts business email buy domain buy hosting buy SSL certificate CalDAV calendar sync callback can't log in cancel hosting cancellation card declined CardDAV catch-all Certbot change domain WordPress change email change nameserver change package change password change payment checklist checkout choose a plan client accounts client area clone WordPress cloud server coming soon page commission company name confirmation link contact contact form Contact Information contacts control panel cPanel cPanel API cPanel contact email cPanel DNS cPanel domains cPanel email cPanel install cPanel language cPanel layout cPanel login cPanel password cPanel SSL cPanel update cPanel users create cPanel account create mailbox credit card cron cron job CRT key CA bundle CSF firewall CSV import currency custom error page Custom Nameservers custom offer dashboard data center database password database privileges database user Database Wizard date.timezone DDNS deceptive site ahead default address delete database delete old emails deny access deploy deposit device email settings Directory Privacy disk space disk usage DKIM DMARC DNS cache DNS explained DNS Records DNS Zone Management document root domain alias domain grace period Domain Hosting Domain Management domain name domain renewal domain transfer downgrade download invoice due date dynamic DNS ElySpace email account email account exists email backup email client email delivery email disk usage email filters email forwarder email history email hosting email login email migration email password email ports email preferences email quota email routing email signature email test email verification EPP code error error log error pages EV SSL expired domain expiry expiry date export database export emails fake email faster support feedback File Manager file permissions firewall first website flush DNS folder force HTTPS forgot password form email not received forward email free migration free SSL FTP account's password FTP password Galaxy email setup getting started Git GitHub Gmail Gmail app GoDaddy good ticket Google malware warning Google sign-in Google Workspace GST number Gzip compression hacked website hacked WordPress hardening help help center home server hosting hosting addons hosting glossary hosting location hosting plan Hosting Service hosting terms hosting tools hosting types hostname hostname SSL hostnamectl hotlink protection HOW TO ADD NAME SERVERS TO MY DOMAIN NAME How to create additional FTP accounts in cPanel How to create FTP accounts in cPanel How to setup name-servers for a domain htaccess htaccess redirect HTTP to HTTPS image theft IMAP IMAP settings IMAP SMTP settings import emails import SQL Imunify360 index.php virus INR install plugin install SSL certificate install WordPress instant answers invite user invoice invoice details invoice emails invoice PDF invoices IP address IP Blocker iPad iPhone email knowledgebase language large database leech protection LEMP Let's Encrypt LFD linked accounts LiteSpeed Cache live chat locked out log out login login email login problem lost email Mac Mac email mail rules mailbox mailbox check mailbox full mailbox size mailing list Mailman maintenance maintenance mode malware removal malware scan manage services mass payment max_execution_time members area memory_limit menu migrate WordPress migration request migration ticket mobile webmail money-back guarantee move email move website move WordPress site MultiPHP INI Editor MultiPHP Manager multiple accounts multiple websites MX record MX records my domains MySQL MySQL database MySQL user mysqldump nameserver Nameservers network drive new account new order newsletter Nginx Node.js notifications npm nvm open ticket Optimize Website or delete order order email out of office outage Outlook Outlook app Outlook IMAP Outlook mobile Outlook password prompt OX App Suite OX webmail page speed password protect pay all pay invoice payment payment details payment failed payment method payment methods PayPal permalinks permissions phishing phone support PHP errors PHP timezone PHP version PHP-FPM php.ini PHPMailer phpMyAdmin plugin updates point domain print invoice printer SMTP product addons products professional email profile public_html publish a post quick start quota quote quotes rating Raw Access raw access logs reading settings redemption period redirect referral link refund register register domain remove user renew domain renewal repair database reseller hosting reset admin password reset password resource usage restore WordPress revoke access revoke privileges root login Roundcube Roundcube export Roundcube identities Roundcube signature rsync backup Samsung Email scam scan to email scheduled task search Search Console self-hosted WordPress send and receive send as server IP address server location server security server status service details services session setup setup domain i setup domain name shared passwords shared vs VPS sign up single sign-on site address Sitejet Builder SMTP SMTP settings spam spam filter SpamAssassin SPF SSH SSH hardening SSH key SSL certificate static front page strong password subaccount subdomain suggestions support ticket support ticket tips support tickets suspension switch account tar test site Thunderbird ticket reply ticket status track delivery transfer website troubleshooting two-factor authentication UAPI Ubuntu Ubuntu 24.04 UFW unpaid invoice unsubscribe unzip upcp upgrade hosting UPI upload files upload_max_filesize URL forwarding user management User Manager username vacation reply VAT ID verify email Web Disk web hosting web hosting basics web server WebDAV webmail webmail From address webmail on phone webmail password website builder website email website migration website not loading Website Performance website security welcome email WhatsApp WhatsApp support whitelist WHM wildcard SSL WordPress 404 WordPress backup WordPress caching WordPress critical error WordPress email WordPress errors WordPress homepage WordPress hosting WordPress login WordPress malware WordPress Management WordPress menu WordPress offline WordPress pages WordPress password WordPress plugins WordPress post WordPress security WordPress SMTP WordPress speed WordPress staging WordPress themes WordPress transfer WordPress update WordPress URL WordPress.org vs WordPress.com WP Mail SMTP wp-admin wp-admin login wp-cron zip Zone Editor zone templates