How to Install LEMP Stack 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
| Task | Command |
|---|---|
| Update package index | sudo apt update |
| Install Nginx | sudo apt install nginx |
| Install MySQL | sudo apt install mysql-server |
| Install PHP-FPM | sudo apt install php-fpm php-mysql |
| Secure MySQL | sudo mysql_secure_installation |
| Restart PHP-FPM | sudo systemctl restart php8.5-fpm |
| Reload Nginx | sudo systemctl reload nginx |
| Test Nginx config | sudo nginx -t |
| Allow HTTP/HTTPS | sudo ufw allow 'Nginx Full' |
| PHP-FPM socket | /run/php/php8.5-fpm.sock |
Prerequisites
Before installing the stack, make sure you have:
- A server running Ubuntu 26.04 with a user with sudo privileges .
- The UFW firewall enabled. If you have not configured it yet, see ufw Command in Linux: Uncomplicated Firewall Reference .
Step 1: Install Nginx
Nginx is in the default Ubuntu 26.04 repositories. Refresh the package index and install it:
sudo apt update
sudo apt install nginxOnce the install finishes, the service starts automatically. Confirm it is running:
sudo systemctl status nginxThe output shows the service as active (running). If UFW is enabled, allow HTTP and HTTPS traffic:
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:
sudo apt install mysql-serverOnce the install completes, run the security script. It walks you through removing anonymous users, disabling remote root login, and dropping the test database:
sudo mysql_secure_installationWhen 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:
sudo systemctl status mysqlFor 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:
sudo apt update
sudo apt install php-fpm php-mysqlOn Ubuntu 26.04 this pulls in PHP 8.5. Confirm the version:
php -vThe 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:
sudo systemctl status php8.5-fpmIf you need extra extensions such as php-curl, php-gd, php-mbstring, php-xml, or php-zip, install them now:
sudo apt install php-curl php-gd php-mbstring php-xml php-zipFor 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:
sudo mkdir -p /var/www/example.com
sudo chown -R $USER:$USER /var/www/example.comCreate a new server block configuration:
sudo nano /etc/nginx/sites-available/example.comPaste the following content. Replace example.com with your domain or your server IP if you do not have a domain yet:
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:
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:
sudo unlink /etc/nginx/sites-enabled/defaultTest the configuration before reloading:
sudo nginx -tThe output should end with syntax is ok and test is successful. Reload Nginx to apply the change:
sudo systemctl reload nginxStep 5: Test the PHP Setup
Create a simple PHP info file to confirm that Nginx hands PHP requests to PHP-FPM:
echo "<?php phpinfo();" | sudo tee /var/www/example.com/info.phpOpen 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:
sudo rm /var/www/example.com/info.phpStep 6: Test the MySQL Connection from PHP
To confirm that PHP can talk to MySQL, create a test database and user:
sudo mysqlIn the MySQL prompt, run:
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;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:
sudo nano /var/www/example.com/db-test.phpAdd the following content:
<?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:
sudo rm /var/www/example.com/db-test.phpTroubleshooting
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.




