Tutorials

Setting Up a LEMP Stack (Linux, Nginx, MySQL, PHP) on VPS

Administrator
By Administrator
Published Oct 02, 2025
7 min read
Setting Up a LEMP Stack (Linux, Nginx, MySQL, PHP) on VPS

Setting Up a LEMP Stack (Linux, Nginx, MySQL, PHP) on VPS

So you've got a VPS and want to host your own website? Awesome! Setting up a LEMP stack is one of the most reliable ways to run dynamic websites. Don't let the acronym intimidate you – it's just Linux (your server's OS), Nginx (the web server), MySQL (the database), and PHP (the programming language that powers WordPress, Laravel, and countless other applications).

I remember my first LEMP setup. I spent hours reading scattered tutorials, running into confusing errors, and questioning my life choices. But here's the thing: once you understand how these pieces fit together, it becomes surprisingly straightforward.

In this guide, I'll walk you through the entire process, from a fresh Ubuntu server to a fully functional LEMP stack ready for your website. Let's get started! 🚀

1. Prerequisites: Getting Your Server Ready

Before we dive in, let's make sure you have everything you need:

  • Ubuntu 20.04 or 22.04 VPS (most providers offer this)
  • SSH access with sudo privileges
  • A domain name pointed to your server (optional but recommended)
  • About 30-45 minutes of your time

First things first, let's connect to your server and update everything:

ssh root@your_server_ip
apt update && apt upgrade -y

This ensures we start with the latest security patches and package versions. Trust me, skipping this step often leads to headaches later.

2. Installing Nginx: Your High-Performance Web Server

Nginx (pronounced "engine-x") is the web server that will handle incoming requests and serve your website files. It's known for being incredibly fast and efficient.

Step 2.1: Install Nginx

apt install nginx -y

Step 2.2: Start and Enable Nginx

systemctl start nginx
systemctl enable nginx

Step 2.3: Configure the Firewall

ufw allow 'Nginx Full'
ufw enable

Step 2.4: Verify Nginx is Working

Open your browser and navigate to http://your_server_ip. You should see the Nginx welcome page. If you do, congrats! Your web server is running.

3. Installing MySQL: Your Database Server

Every dynamic website needs a database to store information – blog posts, user accounts, products, you name it. MySQL is the most popular choice for web applications.

Step 3.1: Install MySQL Server

apt install mysql-server -y

Step 3.2: Secure Your MySQL Installation

This is crucial for security. Run the security script:

mysql_secure_installation

You'll be asked several questions. Here's what I recommend:

Would you like to setup VALIDATE PASSWORD PLUGIN? Y
Please enter 0 = LOW, 1 = MEDIUM and 2 = STRONG: 1
New password: [create a strong password]
Re-enter new password: [confirm password]
Remove anonymous users? Y
Disallow root login remotely? Y
Remove test database and access to it? Y
Reload privilege tables now? Y

Step 3.3: Test MySQL Connection

mysql -u root -p

Enter the password you just created. If you can log in successfully, you're good to go. Type exit to leave the MySQL prompt.

4. Installing PHP: The Programming Language

PHP is what makes your website dynamic. It processes code, interacts with the database, and generates HTML that browsers can understand.

Step 4.1: Install PHP and Essential Extensions

apt install php-fpm php-mysql php-curl php-gd php-mbstring php-xml php-zip -y

These extensions cover most common web applications:

  • php-mysql: For database connectivity
  • php-curl: For making HTTP requests
  • php-gd: For image processing
  • php-mbstring: For handling multi-byte strings
  • php-xml: For XML processing
  • php-zip: For ZIP file handling

Step 4.2: Verify PHP-FPM is Running

systemctl status php8.1-fpm

(Your PHP version might be different - adjust accordingly)

If it's not running, start and enable it:

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

5. Configuring Nginx to Work with PHP

Now comes the magic – we need to tell Nginx how to handle PHP files by passing them to PHP-FPM for processing.

Step 5.1: Create a New Nginx Configuration

nano /etc/nginx/sites-available/your_domain

Step 5.2: Add the LEMP Stack Configuration

server {
    listen 80;
    server_name your_domain.com www.your_domain.com;
    root /var/www/your_domain;
    index index.php index.html index.htm;

    # Handle static files
    location / {
        try_files $uri $uri/ /index.php?$query_string;
    }

    # Pass PHP scripts to PHP-FPM
    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;
    }

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

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

Step 5.3: Enable Your Site

ln -s /etc/nginx/sites-available/your_domain /etc/nginx/sites-enabled/
nginx -t
systemctl reload nginx

The nginx -t command tests your configuration for syntax errors before applying changes.

6. Setting Up Your Website Directory

Let's create the directory for your website and set proper permissions.

Step 6.1: Create Web Directory

mkdir -p /var/www/your_domain

Step 6.2: Create a Test PHP File

nano /var/www/your_domain/index.php

Add this simple PHP test:

<?php
echo "<h1>LEMP Stack is Working! 🎉</h1>";
echo "<p>PHP Version: " . phpversion() . "</p>";
echo "<p>Server Time: " . date('Y-m-d H:i:s') . "</p>";

// Test database connection
$mysqli = new mysqli("localhost", "root", "your_mysql_password");
if ($mysqli->connect_error) {
    echo "<p>Database connection failed</p>";
} else {
    echo "<p>Database connection successful! ✅</p>";
    $mysqli->close();
}

phpinfo();
?>

Step 6.3: Set Proper Permissions

chown -R www-data:www-data /var/www/your_domain
chmod -R 755 /var/www/your_domain

7. Creating a Database for Your Website

Let's create a dedicated database and user for your website.

Step 7.1: Log into MySQL

mysql -u root -p

Step 7.2: Create Database and User

Run these SQL commands:

CREATE DATABASE mywebsite;
CREATE USER 'websiteuser'@'localhost' IDENTIFIED BY 'SecurePassword123!';
GRANT ALL PRIVILEGES ON mywebsite.* TO 'websiteuser'@'localhost';
FLUSH PRIVILEGES;
EXIT;

Replace SecurePassword123! with an actual secure password.

8. Performance and Security Optimizations

A basic LEMP stack works, but let's make it production-ready.

Step 8.1: Optimize PHP-FPM

Edit the PHP-FPM pool configuration:

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

Find and adjust these settings based on your server's RAM:

; For a 1-2GB RAM server
pm.max_children = 10
pm.start_servers = 2
pm.min_spare_servers = 1
pm.max_spare_servers = 3

Restart PHP-FPM:

systemctl restart php8.1-fpm

Step 8.2: Configure MySQL Settings

Edit the MySQL configuration:

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

Add these optimizations under [mysqld]:

innodb_buffer_pool_size = 256M
innodb_log_file_size = 64M
max_connections = 100

Restart MySQL:

systemctl restart mysql

9. Testing Your LEMP Stack

Everything should be ready! Let's test it:

  1. Web Server: Visit http://your_domain.com - you should see your PHP test page
  2. Database: The test page should show "Database connection successful!"
  3. PHP Processing: The phpinfo() output should display without errors

10. Next Steps: What to Do With Your LEMP Stack

Your LEMP stack is ready! Here's what you can do next:

Install WordPress

cd /var/www/your_domain
wget https://wordpress.org/latest.tar.gz
tar -xzvf latest.tar.gz
mv wordpress/* .
rm -rf wordpress latest.tar.gz

Set Up SSL with Let's Encrypt

apt install certbot python3-certbot-nginx -y
certbot --nginx -d your_domain.com

Configure Automated Backups

Consider setting up automated database backups:

crontab -e

Add this line for daily backups at 2 AM:

0 2 * * * mysqldump -u websiteuser -p'SecurePassword123!' mywebsite > /backups/mywebsite_$(date +\%Y\%m\%d).sql

Common Troubleshooting Issues

502 Bad Gateway Error: PHP-FPM isn't responding. Check:

systemctl status php8.1-fpm
tail -f /var/log/nginx/error.log

403 Forbidden Error: Permission issues. Fix with:

chown -R www-data:www-data /var/www/your_domain
chmod -R 755 /var/www/your_domain

Database Connection Failed: Check MySQL is running:

systemctl status mysql

Final Thoughts

And there you have it! 🎉 You've successfully set up a complete LEMP stack from scratch. This powerful combination serves as the foundation for countless websites, from small blogs to large-scale applications.

The beauty of the LEMP stack is its flexibility and performance. Nginx handles concurrent connections efficiently, MySQL provides reliable data storage, and PHP-FPM ensures your dynamic content is processed quickly.

Remember, this is just the beginning. You can optimize further, add caching layers, implement advanced security measures, and scale as your needs grow. But for now, you have a solid, production-ready web server setup.

Happy hosting! 🚀

Related Articles

How to Backup and Restore a Website on VPS Linux

How to Backup and Restore a Website on VPS Linux

Oct 03, 2025

How to Backup and Restore a Website on VPS Linux That moment when you realize your website is gon...

Setting Up Load Balancing with Nginx for High Traffic Sites

Setting Up Load Balancing with Nginx for High Traffic Sites

Oct 03, 2025

Setting Up Load Balancing with Nginx for High Traffic Sites Your website is growing. Traffic is i...

How to Monitor Server Resources with htop and netstat

How to Monitor Server Resources with htop and netstat

Oct 03, 2025

How to Monitor Server Resources with htop and netstat Ever wonder why your website suddenly slows...

Basic Firewall Configuration for Linux Web Servers

Basic Firewall Configuration for Linux Web Servers

Oct 03, 2025

Basic Firewall Configuration for Linux Web Servers Your web server is like a house in a busy neig...