BLOG POSTS
    MangoHost Blog / How to Install Linux Nginx MySQL PHP (LEMP) Stack on Ubuntu
How to Install Linux Nginx MySQL PHP (LEMP) Stack on Ubuntu

How to Install Linux Nginx MySQL PHP (LEMP) Stack on Ubuntu

The LEMP stack is a powerful combination of Linux, Nginx, MySQL, and PHP that provides a robust foundation for web applications and dynamic websites. Unlike the more commonly discussed LAMP stack (which uses Apache), LEMP leverages Nginx’s superior performance for high-traffic scenarios and efficient resource utilization. This guide will walk you through the complete installation process on Ubuntu, covering everything from initial setup to configuration optimization, common troubleshooting scenarios, and performance tuning that you’ll actually need in production environments.

What is LEMP and How Does it Work

LEMP represents four key components working together to serve dynamic web content. Linux provides the operating system foundation, Nginx handles HTTP requests and serves static content with exceptional efficiency, MySQL manages database operations, and PHP processes server-side scripts. The architecture flow typically works like this: incoming requests hit Nginx first, which either serves static files directly or passes PHP requests to PHP-FPM (FastCGI Process Manager), which then communicates with MySQL when database operations are needed.

The real advantage of LEMP over LAMP comes down to Nginx’s event-driven architecture versus Apache’s process-based approach. While Apache creates a new thread or process for each connection, Nginx can handle thousands of concurrent connections with minimal memory overhead. This makes LEMP particularly effective for high-traffic applications, API endpoints, and scenarios where you need to serve many simultaneous users.

Component LEMP Stack LAMP Stack Key Difference
Web Server Nginx Apache Event-driven vs Process-based
Memory Usage ~2-4MB per worker ~8-25MB per process Nginx uses significantly less RAM
Concurrent Connections 10,000+ 400-1000 Nginx handles more simultaneous users
Configuration Simple config files .htaccess support Apache more flexible for shared hosting

Prerequisites and System Preparation

Before diving into the installation, make sure you have a fresh Ubuntu server (18.04, 20.04, or 22.04 work well) with root access or sudo privileges. You’ll also want at least 1GB of RAM, though 2GB is recommended for production use. If you’re running this on a VPS, services like MangoHost VPS provide pre-configured Ubuntu instances that work perfectly for LEMP setups.

First, update your system packages:

sudo apt update && sudo apt upgrade -y

Install some essential packages that you’ll likely need:

sudo apt install curl wget gnupg2 software-properties-common apt-transport-https ca-certificates lsb-release

Installing Nginx Web Server

Nginx installation on Ubuntu is straightforward, but there are a few approaches depending on whether you want the stable repository version or the latest mainline release. For most production scenarios, the stable version works perfectly:

sudo apt install nginx -y

Start and enable Nginx to run automatically on boot:

sudo systemctl start nginx
sudo systemctl enable nginx

Verify the installation by checking the status:

sudo systemctl status nginx

You should see output indicating Nginx is active and running. Test it by visiting your server’s IP address in a browser – you’ll see the default Nginx welcome page.

For those who need the latest features, you can add the official Nginx repository:

curl -fsSL https://nginx.org/keys/nginx_signing.key | sudo apt-key add -
sudo add-apt-repository "deb http://nginx.org/packages/ubuntu $(lsb_release -cs) nginx"
sudo apt update
sudo apt install nginx -y

The key configuration files you’ll work with are:

  • /etc/nginx/nginx.conf – Main configuration file
  • /etc/nginx/sites-available/ – Site configuration files
  • /etc/nginx/sites-enabled/ – Symlinks to active sites
  • /var/log/nginx/ – Access and error logs

Installing MySQL Database Server

MySQL installation has become slightly more complex since Ubuntu started including MySQL 8.0 by default, which uses a different authentication method. Here’s how to install and configure it properly:

sudo apt install mysql-server -y

Run the security installation script to set up basic security measures:

sudo mysql_secure_installation

This script will ask several questions. Here are the recommended responses:

  • Set up VALIDATE PASSWORD plugin: Yes (choose strength level based on your needs)
  • Set root password: Yes (use a strong password)
  • Remove anonymous users: Yes
  • Disallow root login remotely: Yes (unless you specifically need remote root access)
  • Remove test database: Yes
  • Reload privilege tables: Yes

MySQL 8.0 uses caching_sha2_password authentication by default, which can cause issues with some PHP applications. If you encounter authentication problems, you might need to create a user with the older authentication method:

sudo mysql -u root -p

Then in the MySQL prompt:

CREATE USER 'your_user'@'localhost' IDENTIFIED WITH mysql_native_password BY 'your_password';
GRANT ALL PRIVILEGES ON *.* TO 'your_user'@'localhost' WITH GRANT OPTION;
FLUSH PRIVILEGES;
EXIT;

Check MySQL status to ensure it’s running:

sudo systemctl status mysql

Installing PHP and PHP-FPM

PHP installation involves several components. You’ll need PHP itself, PHP-FPM (FastCGI Process Manager) to interface with Nginx, and various PHP extensions for common functionality:

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

The specific PHP version installed depends on your Ubuntu version. Ubuntu 20.04 installs PHP 7.4, while 22.04 installs PHP 8.1. You can check your PHP version:

php -v

Start and enable PHP-FPM:

sudo systemctl start php8.1-fpm  # Replace 8.1 with your PHP version
sudo systemctl enable php8.1-fpm

PHP-FPM configuration files are located at:

  • /etc/php/8.1/fpm/php.ini – Main PHP configuration
  • /etc/php/8.1/fpm/pool.d/www.conf – PHP-FPM pool configuration
  • /var/log/php8.1-fpm.log – PHP-FPM logs

For production environments, you’ll want to adjust some PHP settings. Edit the php.ini file:

sudo nano /etc/php/8.1/fpm/php.ini

Key settings to consider:

upload_max_filesize = 64M
post_max_size = 64M
max_execution_time = 300
max_input_vars = 3000
memory_limit = 256M

After making changes, restart PHP-FPM:

sudo systemctl restart php8.1-fpm

Configuring Nginx to Work with PHP

This is where many people run into issues. Nginx doesn’t have built-in PHP support like Apache’s mod_php, so you need to configure it to pass PHP requests to PHP-FPM. Create a new server block configuration:

sudo nano /etc/nginx/sites-available/your-domain.com

Here’s a complete, production-ready configuration:

server {
    listen 80;
    server_name your-domain.com www.your-domain.com;
    root /var/www/your-domain.com;

    index index.php index.html index.htm;

    location / {
        try_files $uri $uri/ =404;
    }

    location ~ \.php$ {
        include snippets/fastcgi-php.conf;
        fastcgi_pass unix:/var/run/php/php8.1-fpm.sock;
        fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
        include fastcgi_params;
    }

    location ~ /\.ht {
        deny all;
    }

    # Optional: Enable gzip compression
    gzip on;
    gzip_vary on;
    gzip_min_length 1024;
    gzip_types text/plain text/css text/xml text/javascript application/javascript application/xml+rss application/json;

    # Security headers
    add_header X-Frame-Options "SAMEORIGIN" always;
    add_header X-XSS-Protection "1; mode=block" always;
    add_header X-Content-Type-Options "nosniff" always;
}

Create the document root directory:

sudo mkdir -p /var/www/your-domain.com
sudo chown -R www-data:www-data /var/www/your-domain.com
sudo chmod -R 755 /var/www/your-domain.com

Enable the site by creating a symbolic link:

sudo ln -s /etc/nginx/sites-available/your-domain.com /etc/nginx/sites-enabled/

Test the Nginx configuration:

sudo nginx -t

If the test passes, reload Nginx:

sudo systemctl reload nginx

Testing Your LEMP Stack

Create a PHP info file to test the entire stack:

sudo nano /var/www/your-domain.com/info.php

Add this content:

<?php
phpinfo();
?>

Visit http://your-domain.com/info.php in your browser. You should see the PHP information page showing PHP version, loaded modules, and configuration details.

Test MySQL connectivity with a simple PHP script:

sudo nano /var/www/your-domain.com/test-db.php
<?php
$servername = "localhost";
$username = "your_user";
$password = "your_password";

try {
    $pdo = new PDO("mysql:host=$servername", $username, $password);
    $pdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
    echo "Connected successfully to MySQL";
} catch(PDOException $e) {
    echo "Connection failed: " . $e->getMessage();
}
?>

Remember to delete these test files once you’ve verified everything works:

sudo rm /var/www/your-domain.com/info.php /var/www/your-domain.com/test-db.php

Performance Optimization and Best Practices

A basic LEMP installation works, but production environments need optimization. Here are configurations that actually make a difference:

First, optimize Nginx worker processes. Edit the main configuration:

sudo nano /etc/nginx/nginx.conf

Key optimizations:

worker_processes auto;
worker_connections 1024;
keepalive_timeout 65;
client_max_body_size 64m;

# Add in http block
gzip on;
gzip_comp_level 6;
gzip_types text/plain text/css application/json application/javascript text/xml application/xml application/xml+rss text/javascript;

# Enable caching for static files
location ~* \.(jpg|jpeg|png|gif|ico|css|js)$ {
    expires 1M;
    add_header Cache-Control "public, immutable";
}

Optimize PHP-FPM pool settings based on your server’s RAM:

sudo nano /etc/php/8.1/fpm/pool.d/www.conf

For a server with 2GB RAM:

pm = dynamic
pm.max_children = 20
pm.start_servers = 4
pm.min_spare_servers = 2
pm.max_spare_servers = 6
pm.max_requests = 500

MySQL optimization for typical web applications:

sudo nano /etc/mysql/mysql.conf.d/mysqld.cnf

Add these settings under [mysqld]:

innodb_buffer_pool_size = 512M  # 25-75% of available RAM
query_cache_type = 1
query_cache_size = 64M
max_connections = 151
thread_cache_size = 8

Restart all services after optimization:

sudo systemctl restart nginx php8.1-fpm mysql

Common Issues and Troubleshooting

Several issues consistently trip up LEMP installations. Here’s how to diagnose and fix the most common ones:

502 Bad Gateway Error: This usually means Nginx can’t communicate with PHP-FPM. Check if PHP-FPM is running:

sudo systemctl status php8.1-fpm

Verify the socket path in your Nginx configuration matches the PHP-FPM configuration:

grep "listen =" /etc/php/8.1/fpm/pool.d/www.conf

Permission Denied Errors: Usually caused by incorrect file ownership or permissions:

sudo chown -R www-data:www-data /var/www/your-domain.com
sudo find /var/www/your-domain.com -type d -exec chmod 755 {} \;
sudo find /var/www/your-domain.com -type f -exec chmod 644 {} \;

PHP Files Download Instead of Execute: Nginx isn’t configured to process PHP files. Double-check your location block for PHP processing and ensure PHP-FPM is running.

MySQL Connection Refused: Check if MySQL is running and listening on the correct port:

sudo systemctl status mysql
sudo netstat -tlnp | grep mysql

Useful log files for troubleshooting:

  • /var/log/nginx/error.log – Nginx errors
  • /var/log/php8.1-fpm.log – PHP-FPM errors
  • /var/log/mysql/error.log – MySQL errors
  • /var/log/syslog – System-wide logs

Security Considerations

A default LEMP installation isn’t production-ready from a security perspective. Implement these essential security measures:

Configure a firewall using UFW:

sudo ufw allow OpenSSH
sudo ufw allow 'Nginx Full'
sudo ufw enable

Hide Nginx and PHP version information:

# In /etc/nginx/nginx.conf, add to http block:
server_tokens off;

# In /etc/php/8.1/fpm/php.ini:
expose_php = Off

Disable dangerous PHP functions:

# In /etc/php/8.1/fpm/php.ini:
disable_functions = exec,passthru,shell_exec,system,proc_open,popen,curl_exec,curl_multi_exec,parse_ini_file,show_source

Set up SSL certificates using Let’s Encrypt:

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

Real-World Use Cases and Applications

LEMP stacks excel in several scenarios where performance and resource efficiency matter. E-commerce platforms like WooCommerce or Magento benefit significantly from Nginx’s ability to handle concurrent connections and serve static assets efficiently. Content management systems including WordPress, Drupal, and custom PHP applications see improved response times, especially under traffic spikes.

API development is another sweet spot for LEMP. If you’re building REST APIs or microservices with PHP frameworks like Laravel, Symfony, or Slim, the low memory footprint of Nginx means you can run more application instances on the same hardware compared to Apache-based setups.

For high-traffic scenarios, LEMP configurations have been proven to handle 10,000+ concurrent connections on modest hardware. A typical 4GB RAM server can comfortably serve 50-100 requests per second with proper optimization, making it cost-effective for growing applications.

Application Type LEMP Advantages Typical Performance
WordPress Sites Fast static file serving, efficient PHP processing 2-3x faster than LAMP
E-commerce Handles traffic spikes, low resource usage 500+ concurrent users on 2GB RAM
API Endpoints Lightweight, fast JSON responses 1000+ requests/sec on optimized setup
SaaS Applications Scalable, efficient resource utilization Scales horizontally with load balancing

If you’re planning to scale beyond a single server, LEMP stacks work exceptionally well with load balancers and can be easily deployed across multiple servers. For businesses requiring dedicated resources, dedicated server solutions provide the foundation for high-performance LEMP deployments that can handle enterprise-level traffic.

The combination of Nginx’s reverse proxy capabilities with PHP-FPM’s process management makes LEMP particularly suitable for modern web applications that need to integrate with external APIs, handle file uploads, or serve mixed content types efficiently.



This article incorporates information and material from various online sources. We acknowledge and appreciate the work of all original authors, publishers, and websites. While every effort has been made to appropriately credit the source material, any unintentional oversight or omission does not constitute a copyright infringement. All trademarks, logos, and images mentioned are the property of their respective owners. If you believe that any content used in this article infringes upon your copyright, please contact us immediately for review and prompt action.

This article is intended for informational and educational purposes only and does not infringe on the rights of the copyright owners. If any copyrighted material has been used without proper credit or in violation of copyright laws, it is unintentional and we will rectify it promptly upon notification. Please note that the republishing, redistribution, or reproduction of part or all of the contents in any form is prohibited without express written permission from the author and website owner. For permissions or further inquiries, please contact us.

Leave a reply

Your email address will not be published. Required fields are marked