
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 connectivityphp-curl
: For making HTTP requestsphp-gd
: For image processingphp-mbstring
: For handling multi-byte stringsphp-xml
: For XML processingphp-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:
- Web Server: Visit
http://your_domain.com
- you should see your PHP test page - Database: The test page should show "Database connection successful!"
- 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! 🚀