> For the complete documentation index, see [llms.txt](https://mrinalghimire.com.np/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://mrinalghimire.com.np/lemp-stack-documentation/lemp-stack-documentation.md).

# LEMP Stack Documentation

> **Owner:** Mrinal Ghimire\
> **Created:** August 3, 2026\
> **Last Updated:** August 3, 2026\
> **Target System:** Ubuntu 26.04 LTS&#x20;

### About This Documentation

This documentation is owned and maintained by **Mrinal Ghimire**.

It explains how to install and configure a complete **LEMP stack** on a modern Ubuntu server:

* **Linux** — Ubuntu 26.04 LTS
* **Nginx** — Web server
* **MySQL** — Database server
* **PHP / PHP-FPM** — Server-side application processing

The original document supplied for this project targeted Ubuntu 16.04 and PHP 7.0. That platform is obsolete for a new deployment, so this edition has been updated for Ubuntu 26.04 LTS and the current Ubuntu package layout.

{% hint style="info" %}
Ubuntu 26.04 LTS was released on April 23, 2026 and is the current LTS release. Standard security maintenance is scheduled through May 2031. Ubuntu 26.04 includes MySQL 8.4 LTS and PHP 8.5 as the default PHP branch.

Package versions can change as Ubuntu publishes security and maintenance updates. Always verify the installed versions with the commands in this guide.
{% endhint %}

## What Is LEMP?

**LEMP** is a software stack used to host dynamic websites and web applications.

The name represents:

| Component                     | Purpose                          |
| ----------------------------- | -------------------------------- |
| **L** — Linux                 | Operating system                 |
| **E** — Originally “Engine-X” | Nginx web server                 |
| **M** — MySQL                 | Relational database              |
| **P** — PHP                   | Server-side programming language |

Nginx does not execute PHP code directly. PHP requests are passed from Nginx to **PHP-FPM (FastCGI Process Manager)**.

### Request flow

```
Client / Browser
       |
       | HTTP / HTTPS
       v
    Nginx
       |
       | FastCGI
       v
   PHP-FPM
       |
       | SQL queries
       v
     MySQL
```

## Prerequisites

Before starting, make sure you have:

* Ubuntu 26.04 LTS Server
* A user account with `sudo` privileges
* Internet connectivity
* A server IP address or domain name
* SSH access if you are working on a remote server

Check the Ubuntu version:

```bash
lsb_release -a
```

You can also use:

```bash
cat /etc/os-release
```

A typical Ubuntu 26.04 system reports:

```
Ubuntu 26.04 LTS
```

## Installation and Configuration

{% stepper %}
{% step %}

### Update the system

Always update the package index before installing software.

```bash
sudo apt update
```

Upgrade installed packages:

```bash
sudo apt upgrade -y
```

Optional: reboot if the system reports that a reboot is required:

```bash
sudo reboot
```

After reconnecting, verify the system:

```bash
uname -a
```

{% endstep %}

{% step %}

### Install Nginx

Nginx is the web server that accepts HTTP/HTTPS requests and serves website content.

Install Nginx:

```bash
sudo apt install nginx -y
```

Check the service:

```bash
sudo systemctl status nginx
```

If it is not running, start it:

```bash
sudo systemctl start nginx
```

Enable Nginx to start automatically at boot:

```bash
sudo systemctl enable nginx
```

Or do both at once:

```bash
sudo systemctl enable --now nginx
```

Check the installed version:

```bash
nginx -v
```

#### Test Nginx locally

Run:

```bash
curl -I http://127.0.0.1
```

A successful response should contain an HTTP status such as:

```
HTTP/1.1 200 OK
```

You can also check the listening port:

```bash
sudo ss -tlnp | grep :80
```

Nginx normally listens on:

```
80/tcp
```

{% endstep %}

{% step %}

### Configure the UFW firewall

If UFW is enabled, allow SSH and web traffic.

Allow SSH:

```bash
sudo ufw allow OpenSSH
```

Allow HTTP:

```bash
sudo ufw allow 'Nginx HTTP'
```

Allow HTTPS:

```bash
sudo ufw allow 'Nginx HTTPS'
```

Check the firewall:

```bash
sudo ufw status
```

{% hint style="warning" %}
Do not enable UFW on a remote server until you have allowed SSH access. Otherwise, you can lock yourself out of the server.
{% endhint %}

If UFW is currently inactive and you are ready to enable it:

```bash
sudo ufw enable
```

{% endstep %}

{% step %}

### Install MySQL

MySQL stores application and website data.

Install MySQL Server:

```bash
sudo apt install mysql-server -y
```

Check the service:

```bash
sudo systemctl status mysql
```

If required:

```bash
sudo systemctl enable --now mysql
```

Check the installed version:

```bash
mysql --version
```

Ubuntu 26.04 provides the **MySQL 8.4 LTS** series through its repositories.
{% endstep %}

{% step %}

### Secure MySQL

Run the MySQL security utility:

```bash
sudo mysql_secure_installation
```

Follow the prompts shown by your installed MySQL version.

The exact questions can vary between MySQL releases and Ubuntu packages.

The security process is intended to help you:

* Remove anonymous MySQL accounts
* Remove the test database
* Prevent unnecessary remote root access
* Apply safer authentication and password settings

#### Test MySQL

On a default Ubuntu installation, root authentication may use the local Unix socket rather than a traditional password.

Try:

```bash
sudo mysql
```

If the MySQL prompt appears:

```
mysql>
```

Check the server version:

```sql
SELECT VERSION();
```

Exit:

```sql
EXIT;
```

{% endstep %}

{% step %}

### Install PHP and PHP-FPM

PHP processes dynamic application code.

Install PHP-FPM, the MySQL PHP extension, and the PHP command-line interface:

```bash
sudo apt install php-fpm php-mysql php-cli -y
```

Ubuntu 26.04 uses PHP 8.5 as its default PHP branch.

Check the PHP version:

```bash
php -v
```

Check PHP-FPM:

```bash
systemctl status php8.5-fpm
```

Enable and start PHP-FPM:

```bash
sudo systemctl enable --now php8.5-fpm
```

{% endstep %}

{% step %}

### Find the PHP-FPM socket

Nginx communicates with PHP-FPM through a Unix socket.

Check the available PHP-FPM sockets:

```bash
ls -l /run/php/
```

On Ubuntu 26.04 with PHP 8.5, the expected socket is:

```
/run/php/php8.5-fpm.sock
```

You can verify it directly:

```bash
test -S /run/php/php8.5-fpm.sock && echo "PHP-FPM socket exists"
```

{% hint style="info" %}
Always verify the socket on your server instead of blindly copying a PHP version from an older tutorial.
{% endhint %}
{% endstep %}

{% step %}

### Configure PHP

The main PHP-FPM configuration directory is:

```
/etc/php/8.5/fpm/
```

The main PHP configuration file is:

```
/etc/php/8.5/fpm/php.ini
```

Open it when you need to change PHP-FPM settings:

```bash
sudo nano /etc/php/8.5/fpm/php.ini
```

For example, you can review the `cgi.fix_pathinfo` setting:

```bash
grep -E '^[; ]*cgi\.fix_pathinfo' /etc/php/8.5/fpm/php.ini
```

After changing PHP-FPM configuration, restart the service:

```bash
sudo systemctl restart php8.5-fpm
```

{% endstep %}

{% step %}

### Configure Nginx for PHP

Nginx needs a server block that sends `.php` requests to PHP-FPM.

Open the default server configuration:

```bash
sudo nano /etc/nginx/sites-available/default
```

Use a configuration similar to the following:

```nginx
server {
    listen 80 default_server;
    listen [::]:80 default_server;

    root /var/www/html;

    index index.php index.html index.htm;

    server_name _;

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

#### Configuration explained

**`root`**

```nginx
root /var/www/html;
```

This is the website document root.

**`index`**

```nginx
index index.php index.html index.htm;
```

Nginx will look for `index.php` before the other listed index files.

**`server_name`**

```nginx
server_name _;
```

The underscore is commonly used as a catch-all/default server name for a simple server configuration.

For a real domain, replace it with your domain:

```nginx
server_name example.com www.example.com;
```

**PHP location**

```nginx
location ~ \.php$ {
    include snippets/fastcgi-php.conf;
    fastcgi_pass unix:/run/php/php8.5-fpm.sock;
}
```

This sends PHP requests to PHP-FPM.
{% endstep %}

{% step %}

### Test the Nginx configuration

Before reloading Nginx, always test the configuration:

```bash
sudo nginx -t
```

A successful result should look similar to:

```
syntax is ok
test is successful
```

If the test fails, do not reload Nginx until the error is corrected.

Reload Nginx:

```bash
sudo systemctl reload nginx
```

Check the service:

```bash
sudo systemctl status nginx
```

{% endstep %}

{% step %}

### Create a PHP test page

Create a temporary PHP information page:

```bash
sudo nano /var/www/html/info.php
```

Add:

```php
<?php
phpinfo();
```

Save the file.

Open:

```
http://SERVER_IP/info.php
```

Replace `SERVER_IP` with your server IP address.

You should see the PHP information page.

This confirms that:

```
Browser → Nginx → PHP-FPM → PHP
```

is working.
{% endstep %}

{% step %}

### Remove the PHP information page

The `phpinfo()` page exposes detailed information about the PHP environment.

Remove it after testing:

```bash
sudo rm /var/www/html/info.php
```

Verify:

```bash
ls -la /var/www/html/
```

{% endstep %}

{% step %}

### Create a simple PHP application page

Create a basic index page:

```bash
sudo nano /var/www/html/index.php
```

Add:

```php
<?php
echo "<h1>LEMP Stack is Working!</h1>";
echo "<p>Linux + Nginx + MySQL + PHP-FPM</p>";
?>
```

Save the file.

Test locally:

```bash
curl http://127.0.0.1
```

You should receive the HTML generated by PHP.

Open the server IP in a browser:

```
http://SERVER_IP
```

{% endstep %}
{% endstepper %}

## Verify All LEMP Components

### Check Linux

```bash
cat /etc/os-release
```

### Check Nginx

```bash
nginx -v
sudo systemctl is-active nginx
```

### Check MySQL

```bash
mysql --version
sudo systemctl is-active mysql
```

### Check PHP

```bash
php -v
```

### Check PHP-FPM

```bash
php-fpm8.5 -v
sudo systemctl is-active php8.5-fpm
```

### Check listening ports

```bash
sudo ss -tulnp
```

Common LEMP-related ports:

| Port | Service                                                   |
| ---: | --------------------------------------------------------- |
|   22 | SSH                                                       |
|   80 | HTTP / Nginx                                              |
|  443 | HTTPS / Nginx                                             |
| 3306 | MySQL, normally local/private unless deliberately exposed |

{% hint style="info" %}
MySQL does not normally need to be publicly reachable for a standard single-server LEMP deployment.
{% endhint %}

## Useful Service Commands

### Nginx

Start:

```bash
sudo systemctl start nginx
```

Stop:

```bash
sudo systemctl stop nginx
```

Restart:

```bash
sudo systemctl restart nginx
```

Reload configuration:

```bash
sudo systemctl reload nginx
```

Check status:

```bash
sudo systemctl status nginx
```

### MySQL

Start:

```bash
sudo systemctl start mysql
```

Restart:

```bash
sudo systemctl restart mysql
```

Check status:

```bash
sudo systemctl status mysql
```

### PHP-FPM

Start:

```bash
sudo systemctl start php8.5-fpm
```

Restart:

```bash
sudo systemctl restart php8.5-fpm
```

Check status:

```bash
sudo systemctl status php8.5-fpm
```

## Troubleshooting

<details>

<summary>Nginx shows 403 Forbidden</summary>

Check permissions:

```bash
ls -la /var/www/html
```

Check the Nginx error log:

```bash
sudo tail -f /var/log/nginx/error.log
```

Check the directory:

```bash
ls -ld /var/www/html
```

Make sure Nginx can read the website files.

</details>

<details>

<summary>Nginx shows 502 Bad Gateway</summary>

A common cause is that PHP-FPM is not running or Nginx is using the wrong PHP-FPM socket.

Check PHP-FPM:

```bash
sudo systemctl status php8.5-fpm
```

Check the socket:

```bash
ls -l /run/php/
```

Check the Nginx configuration:

```bash
sudo nginx -t
```

Check the Nginx error log:

```bash
sudo tail -f /var/log/nginx/error.log
```

Make sure the Nginx configuration contains the correct socket:

```nginx
fastcgi_pass unix:/run/php/php8.5-fpm.sock;
```

</details>

<details>

<summary>Nginx configuration test fails</summary>

Run:

```bash
sudo nginx -t
```

Then inspect the configuration:

```bash
sudo nano /etc/nginx/sites-available/default
```

Check for:

* Missing semicolons
* Incorrect braces
* Incorrect PHP-FPM socket
* Duplicate `listen` directives
* Incorrect paths

</details>

<details>

<summary>Port 80 is already in use</summary>

Check which process is using port 80:

```bash
sudo ss -tlnp | grep :80
```

If another web server such as Apache is using the port, identify the service:

```bash
sudo systemctl --type=service --state=running
```

Do not stop another web server unless you know it is no longer required.

</details>

## Basic Security Recommendations

A production LEMP server should not stop at installation.

### Keep the system updated

```bash
sudo apt update
sudo apt upgrade -y
```

### Use a non-root administrative account

Avoid performing normal administration directly as root.

### Protect SSH

Use SSH keys where appropriate and avoid exposing unnecessary services.

### Configure UFW

Allow only the ports that are actually required.

### Use HTTPS

For production websites, configure TLS/HTTPS and redirect HTTP traffic to HTTPS.

### Protect MySQL

Do not expose MySQL to the public internet unless remote database access is specifically required and properly restricted.

### Remove test files

Do not leave `phpinfo()` or other diagnostic files on a production server.

### Monitor logs

Useful logs include:

```
/var/log/nginx/access.log
/var/log/nginx/error.log
```

## Useful Verification Checklist

Use this checklist after completing the installation:

* [ ] Ubuntu version verified
* [ ] System packages updated
* [ ] Nginx installed
* [ ] Nginx service running
* [ ] HTTP firewall rule configured
* [ ] HTTPS firewall rule configured
* [ ] MySQL installed
* [ ] MySQL service running
* [ ] MySQL security configuration completed
* [ ] PHP installed
* [ ] PHP-FPM installed
* [ ] PHP-FPM service running
* [ ] PHP-FPM socket verified
* [ ] Nginx configured for PHP
* [ ] `nginx -t` succeeds
* [ ] PHP test page works
* [ ] PHP test page removed
* [ ] LEMP components verified
* [ ] Basic server security reviewed

## Version Reference — August 3, 2026

This documentation targets **Ubuntu 26.04 LTS**&#x20;

The Ubuntu 26.04 package repositories provide:

| Component      | Ubuntu 26.04 target          |
| -------------- | ---------------------------- |
| Ubuntu         | 26.04 LTS                    |
| Nginx          | 1.28.x Ubuntu package series |
| MySQL          | 8.4 LTS                      |
| PHP            | 8.5                          |
| PHP-FPM        | 8.5                          |
| Web root       | `/var/www/html`              |
| PHP-FPM socket | `/run/php/php8.5-fpm.sock`   |

### Upstream version note

Upstream project versions can be newer than the versions shipped by Ubuntu.

As of this documentation's update date:

* Nginx upstream stable: **1.30.4**
* PHP latest 8.5 release: **8.5.8**
* Ubuntu 26.04 provides MySQL **8.4 LTS**
* Ubuntu 26.04 provides PHP **8.5** by default

For a normal Ubuntu server, prefer the Ubuntu repositories unless you have a specific reason to install software directly from an upstream repository.

## Complete Installation Summary

For a fresh Ubuntu 26.04 server, the core installation commands are:

```bash
sudo apt update
sudo apt upgrade -y

sudo apt install nginx -y
sudo systemctl enable --now nginx

sudo ufw allow OpenSSH
sudo ufw allow 'Nginx HTTP'
sudo ufw allow 'Nginx HTTPS'

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

sudo mysql_secure_installation

sudo apt install php-fpm php-mysql php-cli -y
sudo systemctl enable --now php8.5-fpm

sudo nginx -t
sudo systemctl reload nginx
```

Then configure the Nginx server block to pass PHP requests to:

```
/run/php/php8.5-fpm.sock
```

Finally, test the PHP installation through Nginx.

## Conclusion

The LEMP stack provides a reliable foundation for hosting dynamic websites and PHP applications.

The modern Ubuntu 26.04 LTS implementation uses:

```
Ubuntu Linux
     +
Nginx
     +
MySQL 8.4 LTS
     +
PHP 8.5 / PHP-FPM
```

The original supplied documentation was based on Ubuntu 16.04 and PHP 7.0. This version removes those obsolete platform-specific instructions and updates the installation approach for Ubuntu 26.04 LTS.

**Documentation Owner:** Mrinal Ghimire\
**Created:** August 3, 2026\
**Version:** 2.0

### Sources and Verification

This documentation was updated using the supplied LEMP documentation as the starting point and verified against current upstream and Ubuntu information.

* Ubuntu 26.04 LTS release information
* Ubuntu 26.04 package information for Nginx
* Ubuntu 26.04 package information for MySQL 8.4
* Ubuntu 26.04 package information for PHP 8.5
* PHP supported-version information
* Nginx current release information


---

# Agent Instructions
This documentation is published with GitBook. GitBook is the documentation platform designed so that both humans and AI agents can read, navigate, and reason over technical content effectively. Learn more at gitbook.com.

## Querying This Documentation
If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter, and the optional `goal` query parameter:

```
GET https://mrinalghimire.com.np/lemp-stack-documentation/lemp-stack-documentation.md?ask=<question>&goal=<endgoal>
```

`ask` is the immediate question: it should be specific, self-contained, and written in natural language.
`goal` is optional and describes the broader end goal you are ultimately trying to accomplish on behalf of the user. GitBook uses it to tailor the answer towards what is most useful for that goal.

The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
