Technology Encyclopedia Home >How to Set Up a LEMP Stack on Ubuntu — Nginx, MySQL, and PHP-FPM

How to Set Up a LEMP Stack on Ubuntu — Nginx, MySQL, and PHP-FPM

I ran LAMP for a long time. Apache, MySQL, PHP — it did the job. But every time I checked memory usage on a smaller server, Apache was sitting there using RAM even when nothing was happening. Nginx handles the same workload with a noticeably lighter footprint, especially when you're on a budget server or running multiple services on one machine.

Switching to the LEMP stack (Linux, Nginx, MySQL, PHP-FPM) made my PHP apps feel snappier and left more headroom for databases and other processes. It's been my default ever since.

The PHP-FPM part is where new people sometimes get confused — PHP doesn't run inside Nginx the way it does with Apache's mod_php. Instead, PHP-FPM is a separate process manager that Nginx communicates with via a socket. Once you understand that model, the config clicks into place.

This guide installs and configures the full stack on Ubuntu 22.04, including Nginx virtual hosts, PHP-FPM socket configuration, and HTTPS.

I run this on Tencent Cloud Lighthouse with Ubuntu 22.04 LTS. The 2 GB RAM plan handles LEMP comfortably — Nginx's low memory footprint leaves plenty of headroom for your application and database. If you need a LEMP stack specifically for PHP applications like WordPress or Laravel, Lighthouse also offers LNMP application images that pre-configure the entire stack for you. For custom PHP apps where you want more control over the configuration, the manual setup in this guide is the right approach. Lighthouse's console-level firewall also makes it easy to open the right ports without touching the OS-level UFW rules.


Table of Contents

  1. LEMP vs LAMP — When to Choose Which
  2. Part 1 — Install Nginx
  3. Part 2 — Install MySQL and Secure It
  4. Part 3 — Install PHP-FPM
  5. Part 4 — Connect Nginx to PHP-FPM
  6. Part 5 — Test PHP Processing
  7. Part 6 — Create a Database and User
  8. Part 7 — Set Up Virtual Hosts for Multiple Sites
  9. Part 8 — Enable HTTPS with Let's Encrypt
  10. The Gotcha: PHP-FPM Socket Path
  11. Useful Commands

Key Takeaways

  • Use the Lighthouse LNMP application image for instant LEMP stack setup
  • PHP-FPM runs as a separate process — Nginx proxies PHP requests to it via socket
  • The socket path in fastcgi_pass must match the actual PHP-FPM socket (/var/run/php/phpX.X-fpm.sock)
  • Test PHP-FPM is connected: create a .php file that returns phpinfo() output
  • Pool config in /etc/php/X.X/fpm/pool.d/www.conf controls PHP-FPM workers

LEMP vs LAMP — When to Choose Which {#lemp-vs-lamp}

LAMP (Apache) LEMP (Nginx)
Web server Apache Nginx
PHP handler mod_php (in-process) PHP-FPM (separate process)
Memory at idle Higher Lower
.htaccess support Yes (native) No (needs Nginx config equivalent)
Static file performance Good Excellent
Concurrency model Thread/process Event-driven

Choose LEMP when: you want lower memory usage, better static file performance, or plan to run multiple services on the same server.

Choose LAMP when: you're deploying an application that relies heavily on .htaccess directives or Apache-specific modules.

⚡ Shortcut: Tencent Cloud Lighthouse has a pre-built LNMP application image (Linux + Nginx + MySQL + PHP). If you select it when creating your instance, Nginx, MySQL, and PHP-FPM are already installed and configured — skip this entire manual installation. The guide below is for cases where you need precise control over versions or configurations, or where you're adding LEMP to an existing server.


Part 1 — Install Nginx {#part-1}

sudo apt update
sudo apt install -y nginx

sudo systemctl start nginx
sudo systemctl enable nginx

# Open ports
sudo ufw allow 'Nginx Full'

# Verify
curl http://localhost
# Should return the Nginx welcome page HTML

Part 2 — Install MySQL and Secure It {#part-2}

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

# Run security hardening
sudo mysql_secure_installation

Answer the prompts:

  • Set up VALIDATE PASSWORD: Y
  • Remove anonymous users: Y
  • Disallow root login remotely: Y
  • Remove test database: Y
  • Reload privilege tables: Y

Part 3 — Install PHP-FPM {#part-3}

With Nginx, PHP runs as a separate process via PHP-FPM (FastCGI Process Manager) rather than being embedded in the web server. This is slightly more complex to configure but more efficient.

sudo apt install -y php-fpm php-mysql

# Install common PHP extensions
sudo apt install -y \
  php-curl \
  php-gd \
  php-mbstring \
  php-xml \
  php-zip \
  php-intl \
  php-bcmath

# Check the PHP-FPM version that was installed
php-fpm8.1 --version
# Note the version number (8.1 in this example) — you'll need it for Nginx config

PHP-FPM starts automatically and communicates with Nginx via a Unix socket:

# Find the socket path
ls /run/php/
# You should see: php8.1-fpm.sock (or similar)

Note the socket filename — you'll use it in the Nginx configuration.


Part 4 — Connect Nginx to PHP-FPM {#part-4}

Edit the Nginx default site config (or create a new one) to pass PHP requests to PHP-FPM:

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

Replace the contents with:

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

    # Pass PHP scripts to PHP-FPM
    location ~ \.php$ {
        include snippets/fastcgi-php.conf;

        # Update this path to match your PHP-FPM socket
        fastcgi_pass unix:/run/php/php8.1-fpm.sock;
    }

    # Deny access to .htaccess files
    location ~ /\.ht {
        deny all;
    }
}

Test and reload:

sudo nginx -t
sudo systemctl reload nginx

Part 5 — Test PHP Processing {#part-5}

sudo nano /var/www/html/info.php
<?php phpinfo(); ?>

Visit http://YOUR_SERVER_IP/info.php. You should see the PHP info page showing the Nginx server API and PHP-FPM configuration.

Delete the file after testing:

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

Part 6 — Create a Database and User {#part-6}

sudo mysql
CREATE DATABASE myapp;
CREATE USER 'myapp_user'@'localhost' IDENTIFIED BY 'choose_a_strong_password';
GRANT ALL PRIVILEGES ON myapp.* TO 'myapp_user'@'localhost';
FLUSH PRIVILEGES;
EXIT;

Part 7 — Set Up Virtual Hosts for Multiple Sites {#part-7}

sudo mkdir -p /var/www/mysite
sudo chown -R www-data:www-data /var/www/mysite

sudo nano /var/www/mysite/index.php
<?php echo "<h1>mysite.com is running on LEMP.</h1>"; ?>

Create the Nginx site config:

sudo nano /etc/nginx/sites-available/mysite
server {
    listen 80;
    listen [::]:80;

    server_name mysite.com www.mysite.com;
    root /var/www/mysite;
    index index.php index.html;

    access_log /var/log/nginx/mysite_access.log;
    error_log  /var/log/nginx/mysite_error.log;

    location / {
        try_files $uri $uri/ /index.php?$query_string;
    }

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

    location ~ /\.ht {
        deny all;
    }
}
sudo ln -s /etc/nginx/sites-available/mysite /etc/nginx/sites-enabled/
sudo nginx -t && sudo systemctl reload nginx

Part 8 — Enable HTTPS with Let's Encrypt {#part-8}

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

Certbot modifies your Nginx config and handles auto-renewal. Test it:

sudo certbot renew --dry-run

The Gotcha: PHP-FPM Socket Path {#gotcha}

The most common LEMP configuration error: the PHP-FPM socket path in your Nginx config doesn't match the actual socket.

Symptoms: Nginx returns a 502 Bad Gateway when accessing PHP files.

# Find the actual socket path
ls /run/php/
# Example output: php8.1-fpm.pid  php8.1-fpm.sock

# Check your Nginx config uses the correct path
grep fastcgi_pass /etc/nginx/sites-enabled/*

If there's a mismatch, update the fastcgi_pass line in your Nginx config to use the actual socket name, then reload.

Also check PHP-FPM is actually running:

sudo systemctl status php8.1-fpm

If it's not running, start it:

sudo systemctl start php8.1-fpm
sudo systemctl enable php8.1-fpm

Useful Commands {#commands}

# Nginx
sudo nginx -t                           # Test config
sudo systemctl reload nginx             # Reload config
tail -f /var/log/nginx/error.log        # Watch errors

# PHP-FPM
sudo systemctl status php8.1-fpm        # Check status
sudo systemctl restart php8.1-fpm       # Restart
php -v                                  # Check PHP version
php -m                                  # List modules

# MySQL
sudo mysql                              # Connect as root
mysql -u USER -p DATABASE               # Connect as user
mysqldump -u USER -p DB > backup.sql    # Backup database

Troubleshooting {#troubleshooting}

Issue Likely Cause Fix
Connection refused Service not running or wrong port Check systemctl status SERVICE and verify firewall rules
Permission denied Wrong file ownership or permissions Check file ownership with ls -la and use chown/chmod to fix
502 Bad Gateway Backend service not running Restart the backend service; check logs with journalctl -u SERVICE
SSL certificate error Certificate expired or domain mismatch Run sudo certbot renew and verify domain DNS points to server IP
Service not starting Config error or missing dependency Check logs with journalctl -u SERVICE -n 50 for specific error
Out of disk space Logs or data accumulation Run df -h to identify usage; clean logs or attach CBS storage
High memory usage Too many processes or memory leak Check with htop; consider upgrading instance plan if consistently high
Firewall blocking traffic Port not open in UFW or Lighthouse console Open port in Lighthouse console firewall AND sudo ufw allow PORT

Frequently Asked Questions {#faq}

Does Lighthouse have a pre-built LNMP image?
Yes — the LNMP application image comes with Nginx + MySQL + PHP-FPM pre-configured. Select it to skip all manual installation.

What is PHP-FPM and why use it with Nginx?
PHP-FPM is a separate PHP process manager. Nginx communicates with it via a Unix socket, allowing PHP and Nginx to run as independent processes with better resource management.

Where is the PHP-FPM socket located?
On Ubuntu with PHP 8.2: /var/run/php/php8.2-fpm.sock. Reference this path in your Nginx fastcgi_pass directive.

What is the difference between LNMP and LEMP?
Same stack: Linux + Nginx + MySQL + PHP. Different abbreviation spellings, same setup.

How do I run multiple PHP versions on one server?
Install multiple PHP-FPM versions via the ondrej/php PPA. Configure each Nginx site to use the appropriate PHP-FPM socket path.


Launch your cloud server today:
👉 Tencent Cloud Lighthouse — Lightweight Ubuntu VPS
👉 View current pricing and promotions
👉 Explore all active deals and offers