Nginx web server terminal configuration

Install LEMP Stack on VPS Ubuntu: Nginx + MySQL + PHP-FPM

June 2026 · 7 min read

LEMP Stack is a collection of software for running Web Applications consisting of Linux, ENginx (pronounced "engine-x"), MySQL, and PHP-FPM. The key difference from LAMP Stack is the use of Nginx instead of Apache, which provides significantly better performance, especially under high traffic and when serving static files.

This article will guide you through installing LEMP Stack on Ubuntu 22.04 LTS VPS from start to finish, including basic security configuration.

Why Choose LEMP Over LAMP?

Nginx uses an Event-Driven, Non-Blocking I/O architecture, which can handle significantly more concurrent connections compared to Apache's Thread-Based Model. Additionally:

Prerequisites

If you don't have a VPS yet, you can choose an appropriate package from 29vps.com. We recommend a plan with at least 1 GB RAM for running LEMP Stack.

Step 1: Update the System

After SSH-ing into your VPS, always update the package list and upgrade the system first:

sudo apt update && sudo apt upgrade -y

Wait for the process to complete, then reboot if there's a kernel update:

sudo reboot

Step 2: Install Nginx

Install Nginx from the official Ubuntu repository:

sudo apt install nginx -y

Enable it and start it on boot:

sudo systemctl enable nginx
sudo systemctl start nginx

Verify that Nginx is running correctly:

sudo systemctl status nginx

You should see a green active (running) message. Next, open ports 80 and 443 in the firewall:

sudo ufw allow 'Nginx Full'
sudo ufw enable
sudo ufw status
Try opening a browser and entering your VPS IP address. You should see the "Welcome to nginx!" page, confirming that the installation was successful.

Step 3: Install MySQL

Install MySQL Server:

sudo apt install mysql-server -y

Run the secure installation script to set a root password and remove insecure settings:

sudo mysql_secure_installation

The system will ask a series of questions. We recommend answering as follows:

  1. VALIDATE PASSWORD component — Press Y to enable it (recommended)
  2. Password strength — Choose 2 (STRONG) for production
  3. Remove anonymous users — Y
  4. Disallow root login remotely — Y
  5. Remove test database — Y
  6. Reload privilege tables — Y

Log in to MySQL to create a database and user for your website:

sudo mysql -u root -p
-- Create database
CREATE DATABASE mywebsite CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;

-- Create user
CREATE USER 'webuser'@'localhost' IDENTIFIED BY 'StrongPassword123!';

-- Grant privileges
GRANT ALL PRIVILEGES ON mywebsite.* TO 'webuser'@'localhost';

FLUSH PRIVILEGES;
EXIT;
Do not use the example password from this article in production. Create a strong, unique password instead.

Step 4: Install PHP-FPM

PHP-FPM (FastCGI Process Manager) is how Nginx runs PHP, passing requests through a Unix socket instead of loading PHP as a module like Apache does:

sudo apt install php8.1-fpm php8.1-mysql php8.1-curl php8.1-gd \
  php8.1-mbstring php8.1-xml php8.1-zip php8.1-bcmath -y

Verify that PHP-FPM is running:

sudo systemctl status php8.1-fpm

Check the PHP version:

php -v

Step 5: Configure Nginx Virtual Host

Create a configuration file for your domain:

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

Paste the following content (replace example.com with your domain):

server {
    listen 80;
    listen [::]:80;

    server_name example.com www.example.com;
    root /var/www/example.com/html;
    index index.php index.html index.htm;

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

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

    location ~ /\.ht {
        deny all;
    }

    # Cache Static Files
    location ~* \.(jpg|jpeg|png|gif|ico|css|js|woff2)$ {
        expires 30d;
        add_header Cache-Control "public, no-transform";
    }
}

Create the web root directory and test file:

sudo mkdir -p /var/www/example.com/html
sudo chown -R www-data:www-data /var/www/example.com
sudo chmod -R 755 /var/www/example.com

Enable the site and test the configuration:

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

If you see syntax is ok and test is successful, reload Nginx:

sudo systemctl reload nginx

Step 6: Test PHP is Working

Create an info.php file to test:

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

Open your browser to http://example.com/info.php and you should see the PHP Info page displaying all configuration details.

Do not forget to delete the info.php file after testing, as it exposes system information that could be a security vulnerability: sudo rm /var/www/example.com/html/info.php

Step 7: Install SSL with Let's Encrypt (Recommended)

Install Certbot:

sudo apt install certbot python3-certbot-nginx -y

Generate a certificate and automatically configure HTTPS:

sudo certbot --nginx -d example.com -d www.example.com

Certbot will ask for your email and agreement to the Terms of Service, then automatically modify your Nginx config to support HTTPS. The certificate will auto-renew every 90 days. Verify with:

sudo certbot renew --dry-run

Additional PHP-FPM Optimization

Edit PHP configuration for production:

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

Find and modify these values:

upload_max_filesize = 64M
post_max_size = 64M
max_execution_time = 300
memory_limit = 256M
expose_php = Off

Restart PHP-FPM after making changes:

sudo systemctl restart php8.1-fpm

Additional Nginx Optimization

Edit /etc/nginx/nginx.conf to improve performance:

sudo nano /etc/nginx/nginx.conf

Important values to adjust based on your VPS CPU:

worker_processes auto;          # Use all CPU cores automatically
worker_connections 1024;        # Connections per worker
keepalive_timeout 65;
gzip on;                        # Enable Gzip compression
gzip_types text/plain text/css application/json application/javascript;

Summary: LEMP Stack Installation Checklist

After completing all steps, verify the following to ensure your system is ready:

Your LEMP Stack is now ready! The next step is to install a CMS like WordPress or deploy your PHP application into the /var/www/example.com/html/ directory. For WordPress installation specifically on LEMP Stack, you can follow our next article at 29vps.com.

Verify LEMP Stack is Working Correctly

# Verify Nginx config has no syntax errors
sudo nginx -t

# Check status of all services
sudo systemctl status nginx php8.1-fpm mysql

# Test PHP is working through Nginx
echo "<?php echo phpversion(); ?>" | sudo tee /var/www/example.com/html/test.php
curl -s http://localhost/test.php
sudo rm /var/www/example.com/html/test.php

# Verify MySQL connection with your user
mysql -u webuser -p -e "SHOW DATABASES;" mywebsite
Tip: If nginx -t displays both syntax is ok and test is successful at the same time, your config is definitely correct — no guessing needed.

Common Issues & Troubleshooting

Error: 502 Bad Gateway After Setting Up PHP-FPM

This occurs when the PHP-FPM socket path in the Nginx config doesn't match the actual file.

# Check where the socket file actually is
ls /var/run/php/

# If you see php8.3-fpm.sock but config uses php8.1, edit it
sudo nano /etc/nginx/sites-available/example.com
# Change fastcgi_pass unix:/var/run/php/php8.1-fpm.sock;
# to the version that ls shows
sudo systemctl reload nginx

Error: 403 Forbidden When First Accessing the Website

No index.php / index.html file exists in the web root or permissions are incorrect.

# Check web root permissions
ls -la /var/www/example.com/html/

# Fix permissions
sudo chown -R www-data:www-data /var/www/example.com
sudo chmod -R 755 /var/www/example.com

# Create a test index.html file
echo "<h1>Hello LEMP</h1>" | sudo tee /var/www/example.com/html/index.html

PHP Code Not Being Parsed — Seeing Raw PHP Code in Browser

Nginx is not passing .php files to PHP-FPM. Check the location block in your config.

# Verify the location ~ \.php$ block exists in config
grep -n "\.php" /etc/nginx/sites-available/example.com

# Check if PHP-FPM is running
sudo systemctl status php8.1-fpm
# If stopped
sudo systemctl start php8.1-fpm

Certbot Cannot Request Certificate — Challenge Failed

Usually caused by DNS not pointing to your VPS or firewall blocking port 80.

# Verify A record points correctly
dig +short A example.com

# Check if port 80 is open
curl -I http://example.com
sudo ufw status | grep 80

MySQL: ERROR 1045 (28000): Access Denied for User

Password is incorrect or user doesn't have privileges on that database.

# Log in as root and check user
sudo mysql -u root
SELECT user, host FROM mysql.user WHERE user='webuser';
SHOW GRANTS FOR 'webuser'@'localhost';

-- If you need to reset password
ALTER USER 'webuser'@'localhost' IDENTIFIED BY 'NewPassword456!';
FLUSH PRIVILEGES;

Frequently Asked Questions

Can LEMP and LAMP both run WordPress the same way?

Yes, WordPress works the same on both. The main difference is that Nginx requires try_files directives instead of .htaccess that WordPress uses with Apache. Nginx doesn't read .htaccess files at all, so you must translate the rewrite rules into your nginx.conf instead.

How do I upgrade from PHP 8.1 to PHP 8.3?

You can install the new PHP version without removing the old one, then update the path in your Nginx config.

sudo apt install php8.3-fpm php8.3-mysql php8.3-curl php8.3-mbstring -y
# Edit Nginx config and change php8.1-fpm.sock → php8.3-fpm.sock
sudo systemctl reload nginx

Can I run Node.js or Python alongside LEMP after installation?

Yes, because Nginx can act as a reverse proxy. Use location blocks to direct traffic to PHP-FPM, Node.js, or Python apps in a single config file, with each backend running on its own port or socket.