How to Install LEMP Stack on Ubuntu 26.04

By 

Published on

7 min read

LEMP stack installation on Ubuntu 26.04

When you need to host a PHP application or a CMS such as WordPress, Magento, or Laravel on a fresh Ubuntu server, the LEMP stack is one of the most common ways to get there. LEMP stands for Linux, Nginx (pronounced “engine-x”), MySQL, and PHP, and the four pieces fit together to serve dynamic PHP pages over HTTP.

This guide explains how to install and configure a complete LEMP stack on Ubuntu 26.04. By the end you will have Nginx serving HTTP traffic, MySQL 8.4 running as the database, and PHP 8.5 processing dynamic pages through PHP-FPM.

Quick Reference

TaskCommand
Update package indexsudo apt update
Install Nginxsudo apt install nginx
Install MySQLsudo apt install mysql-server
Install PHP-FPMsudo apt install php-fpm php-mysql
Secure MySQLsudo mysql_secure_installation
Restart PHP-FPMsudo systemctl restart php8.5-fpm
Reload Nginxsudo systemctl reload nginx
Test Nginx configsudo nginx -t
Allow HTTP/HTTPSsudo ufw allow 'Nginx Full'
PHP-FPM socket/run/php/php8.5-fpm.sock

Prerequisites

Before installing the stack, make sure you have:

Step 1: Install Nginx

Nginx is in the default Ubuntu 26.04 repositories. Refresh the package index and install it:

Terminal
sudo apt update
sudo apt install nginx

Once the install finishes, the service starts automatically. Confirm it is running:

Terminal
sudo systemctl status nginx

The output shows the service as active (running). If UFW is enabled, allow HTTP and HTTPS traffic:

Terminal
sudo ufw allow 'Nginx Full'

Open http://your_server_ip in a browser. You should see the default Nginx welcome page, which confirms that Nginx is serving requests.

For a deeper walkthrough of the install and the directory layout, see How to Install Nginx on Ubuntu 26.04 .

Step 2: Install MySQL

The database tier handles persistence. Install the MySQL server package:

Terminal
sudo apt install mysql-server

Once the install completes, run the security script. It walks you through removing anonymous users, disabling remote root login, and dropping the test database:

Terminal
sudo mysql_secure_installation

When prompted, answer Y to each hardening question. The validate password component is optional and you can disable it if you plan to manage credentials yourself.

To verify that the service is running:

Terminal
sudo systemctl status mysql

For details on creating users and granting privileges, see How to Install MySQL on Ubuntu 26.04 .

Step 3: Install PHP and PHP-FPM

Nginx does not embed a PHP interpreter. Instead, requests for PHP files are handed off to PHP-FPM (FastCGI Process Manager) over a Unix socket. Install PHP-FPM and the MySQL driver:

Terminal
sudo apt update
sudo apt install php-fpm php-mysql

On Ubuntu 26.04 this pulls in PHP 8.5. Confirm the version:

Terminal
php -v

The output starts with PHP 8.5.x. The PHP-FPM service starts automatically and listens on a Unix socket at /run/php/php8.5-fpm.sock:

Terminal
sudo systemctl status php8.5-fpm

If you need extra extensions such as php-curl, php-gd, php-mbstring, php-xml, or php-zip, install them now:

Terminal
sudo apt install php-curl php-gd php-mbstring php-xml php-zip

For information on additional modules and switching PHP versions, see How to Install PHP on Ubuntu 26.04 .

Step 4: Configure Nginx to Serve PHP

Now that Nginx and PHP-FPM are running, you need a server block that passes .php requests to PHP-FPM. Create a directory for the site and a small test file:

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

Create a new server block configuration:

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

Paste the following content. Replace example.com with your domain or your server IP if you do not have a domain yet:

nginx
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.5-fpm.sock;
    }

    location ~ /\.ht {
        deny all;
    }
}

The try_files directive serves static files when they exist and falls back to a 404 otherwise. The location ~ \.php$ block matches any request ending in .php and forwards it to PHP-FPM through the Unix socket. The final location ~ /\.ht block blocks access to legacy .htaccess files, which Nginx does not use.

Enable the site by creating a symlink in sites-enabled:

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

If the default server block is still enabled, remove its symlink so Nginx serves your new site for matching requests:

Terminal
sudo unlink /etc/nginx/sites-enabled/default

Test the configuration before reloading:

Terminal
sudo nginx -t

The output should end with syntax is ok and test is successful. Reload Nginx to apply the change:

Terminal
sudo systemctl reload nginx

Step 5: Test the PHP Setup

Create a simple PHP info file to confirm that Nginx hands PHP requests to PHP-FPM:

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

Open http://example.com/info.php (or http://your_server_ip/info.php) in a browser. You should see the PHP information page that lists the PHP version, loaded extensions, and configuration directives. If the page shows the source code as plain text, Nginx is not passing the request to PHP-FPM and the location ~ \.php$ block needs to be reviewed.

Once you confirm PHP is working, remove the info file. It exposes details about your environment that should not be publicly readable:

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

Step 6: Test the MySQL Connection from PHP

To confirm that PHP can talk to MySQL, create a test database and user:

Terminal
sudo mysql

In the MySQL prompt, run:

sql
CREATE DATABASE lemp_test;
CREATE USER 'lemp_user'@'localhost' IDENTIFIED BY 'changeme';
GRANT ALL PRIVILEGES ON lemp_test.* TO 'lemp_user'@'localhost';
FLUSH PRIVILEGES;
EXIT;
Warning
The password above is a placeholder. Replace changeme with a strong value, and do not commit credentials to version control. Store secrets in environment variables or a .env file outside the repository.

Create a small connection test:

Terminal
sudo nano /var/www/example.com/db-test.php

Add the following content:

php
<?php
$mysqli = new mysqli("localhost", "lemp_user", "changeme", "lemp_test");
if ($mysqli->connect_error) {
    die("Connection failed: " . $mysqli->connect_error);
}
echo "Connected to MySQL " . $mysqli->server_info;
$mysqli->close();

Open http://example.com/db-test.php. The page prints Connected to MySQL 8.4.x when the credentials and the PHP MySQL driver are working. Remove the file once you confirm the connection:

Terminal
sudo rm /var/www/example.com/db-test.php

Troubleshooting

Nginx shows the welcome page after editing the server block
Nginx still serves the default site. Remove the symlink at /etc/nginx/sites-enabled/default or rename your server block so it loads first, then run sudo nginx -t and sudo systemctl reload nginx.

PHP files download instead of executing
Nginx is not forwarding .php requests to PHP-FPM. Verify that the location ~ \.php$ block exists, that fastcgi_pass points to /run/php/php8.5-fpm.sock, and that PHP-FPM is running with sudo systemctl status php8.5-fpm.

502 Bad Gateway
PHP-FPM is not running, or Nginx is pointing at a wrong socket path. Run ls -l /run/php/ and confirm that the socket file matches the version in your config (for example, php8.5-fpm.sock). Restart the service with sudo systemctl restart php8.5-fpm.

Permission denied accessing the socket
The socket is owned by www-data by default. Make sure Nginx runs as www-data (the default on Ubuntu) and that no custom file permissions on /run/php/ block access.

MySQL connection refused from PHP
Confirm that the php-mysql package is installed, that the user has been granted privileges on the target database, and that the password in the PHP code matches the one used in CREATE USER.

FAQ

What is the difference between LEMP and LAMP?
LEMP uses Nginx as the web server, while LAMP uses Apache. Nginx handles many concurrent connections with low memory and is a strong fit for static content and reverse proxying. Apache supports per-directory .htaccess files and mod_php, which simplifies shared hosting setups. For a step-by-step Apache install, see How to Install LAMP Stack on Ubuntu 26.04 .

Can I use MariaDB instead of MySQL?
Yes. MariaDB is a drop-in replacement for MySQL and uses the same client tools, the same protocol, and the same SQL syntax for the cases covered in this guide.

Which PHP-FPM socket path do I use?
The path follows the PHP version. On Ubuntu 26.04 with the default PHP 8.5, the socket is /run/php/php8.5-fpm.sock. If you install another version, list /run/php/ to find the right socket file.

How do I add HTTPS to the site?
The recommended path is to install Certbot and request a Let’s Encrypt certificate for your domain. The Certbot Nginx plugin updates the server block automatically and sets up redirection from HTTP to HTTPS.

Next Steps

You now have a working LEMP stack on Ubuntu 26.04. From here you can deploy a PHP application, create additional Nginx server blocks for more sites, or front the stack with HTTPS using Let’s Encrypt.

Linuxize Weekly Newsletter

A quick weekly roundup of new tutorials, news, and tips.

About the authors

Dejan Panovski

Dejan Panovski

Dejan Panovski is the founder of Linuxize, an RHCSA-certified Linux system administrator and DevOps engineer based in Skopje, Macedonia. Author of 800+ Linux tutorials with 20+ years of experience turning complex Linux tasks into clear, reliable guides.

View author page