How to Install Nginx + PHP-FPM + MariaDB on Ubuntu VPS: 2025 LEMP Stack Guide
The LEMP stack — Linux, Nginx, MySQL/MariaDB, and PHP — is the most popular combination for hosting PHP applications on a VPS. Compared to the older Apache-based LAMP stack, Nginx handles concurrent connections more efficiently, making it the preferred choice for production environments where performance under load matters. This guide covers the complete LEMP stack installation on Ubuntu 22.04 LTS, with configuration tuned for real-world WordPress and PHP application workloads.
Why Choose Nginx + PHP-FPM Over Apache + mod_php?
Apache with mod_php was the default for over a decade, but Nginx + PHP-FPM has become the standard for performance-critical deployments for several reasons:
- Event-driven architecture — Nginx handles thousands of concurrent connections with a fixed number of worker processes, using minimal memory per connection
- PHP-FPM process management — PHP executes in a separate FastCGI process pool, allowing independent tuning and isolation from the web server
- Better static file serving — Nginx serves static assets (images, CSS, JS) with extremely low overhead, freeing PHP processes for dynamic content only
- Reverse proxy capabilities — Nginx excels as a reverse proxy in front of Node.js, Python, or other application servers
Prerequisites
This guide assumes:
- Ubuntu 22.04 LTS VPS with root or sudo access
- SSH access to your server
- A domain name pointed to your server’s IP (for SSL setup)
Step 1: Update the System
sudo apt update && sudo apt upgrade -y
Step 2: Install Nginx
sudo apt install nginx -y
sudo systemctl enable nginx
sudo systemctl start nginx
Verify Nginx is running:
sudo systemctl status nginx
Open your server’s IP in a browser — the Nginx default welcome page confirms successful installation.
Nginx Performance Tuning
Edit the main Nginx configuration for better performance:
sudo nano /etc/nginx/nginx.conf
Key settings to optimize:
worker_processes auto;
worker_connections 1024;
keepalive_timeout 65;
gzip on;
gzip_types text/plain text/css application/json application/javascript text/xml;
gzip_min_length 256;
The worker_processes auto setting matches the number of worker processes to available CPU cores. gzip on enables on-the-fly compression, reducing transfer size for text-based responses by 60–80%.
Step 3: Install PHP-FPM 8.2
Ubuntu 22.04 ships with PHP 8.1 in its default repositories. For PHP 8.2, add the Ondrej Sury PPA:
sudo apt install software-properties-common -y
sudo add-apt-repository ppa:ondrej/php -y
sudo apt update
Install PHP-FPM and the extensions required for WordPress and most PHP applications:
sudo apt install php8.2-fpm php8.2-mysql php8.2-curl php8.2-gd php8.2-mbstring php8.2-xml php8.2-zip php8.2-bcmath php8.2-intl php8.2-soap php8.2-redis -y
Enable and start PHP-FPM:
sudo systemctl enable php8.2-fpm
sudo systemctl start php8.2-fpm
Verify the PHP-FPM socket exists:
ls /var/run/php/php8.2-fpm.sock
PHP-FPM Pool Configuration
Tune the PHP-FPM worker pool for your server’s RAM. Edit the default pool:
sudo nano /etc/php/8.2/fpm/pool.d/www.conf
For a 2 GB RAM server with WordPress:
pm = dynamic
pm.max_children = 20
pm.start_servers = 4
pm.min_spare_servers = 2
pm.max_spare_servers = 6
pm.max_requests = 500
The pm.max_children value should be calculated as: available RAM (minus OS overhead) divided by average PHP process size. On WordPress, each PHP-FPM process typically uses 40–60 MB. For 2 GB RAM with ~500 MB reserved for the OS and database: (1500 MB / 50 MB) = ~30 max children.
Enable PHP OPcache
OPcache stores precompiled PHP scripts in memory, eliminating the need to recompile on every request — one of the most impactful WordPress performance optimizations:
sudo nano /etc/php/8.2/fpm/conf.d/10-opcache.ini
Recommended OPcache settings:
opcache.enable=1
opcache.memory_consumption=128
opcache.interned_strings_buffer=16
opcache.max_accelerated_files=10000
opcache.revalidate_freq=2
opcache.save_comments=1
Restart PHP-FPM after changes:
sudo systemctl restart php8.2-fpm
Step 4: Install MariaDB
MariaDB is a drop-in MySQL replacement with better performance characteristics for web applications:
sudo apt install mariadb-server -y
sudo systemctl enable mariadb
sudo systemctl start mariadb
Run the security hardening script:
sudo mysql_secure_installation
At the prompts: set a strong root password, remove anonymous users, disallow remote root login, remove the test database, and reload privilege tables.
MariaDB Performance Tuning
Edit the MariaDB configuration for better performance:
sudo nano /etc/mysql/mariadb.conf.d/50-server.cnf
Key settings for a 2 GB RAM server:
innodb_buffer_pool_size = 512M
innodb_log_file_size = 128M
innodb_flush_log_at_trx_commit = 2
query_cache_type = 0
query_cache_size = 0
max_connections = 150
The innodb_buffer_pool_size should be set to approximately 25–50% of total RAM for a dedicated database server, or 20–30% when sharing RAM with Nginx and PHP-FPM. Disabling the query cache (query_cache_type = 0) is recommended for MariaDB 10.6+ as it causes more problems than it solves under concurrent load.
Create an Application Database and User
sudo mysql -u root -p
CREATE DATABASE wordpress_db CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
CREATE USER 'wp_user'@'localhost' IDENTIFIED BY 'YourStrongPassword!';
GRANT ALL PRIVILEGES ON wordpress_db.* TO 'wp_user'@'localhost';
FLUSH PRIVILEGES;
EXIT;
Step 5: Configure Nginx for Your PHP Application
Create an Nginx server block for your domain. This example is optimized for WordPress:
sudo nano /etc/nginx/sites-available/yourdomain.com
server {
listen 80;
server_name yourdomain.com www.yourdomain.com;
root /var/www/yourdomain.com;
index index.php index.html;
# 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;
# WordPress permalinks
location / {
try_files $uri $uri/ /index.php?$args;
}
# PHP-FPM processing
location ~ \.php$ {
include snippets/fastcgi-php.conf;
fastcgi_pass unix:/var/run/php/php8.2-fpm.sock;
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
include fastcgi_params;
}
# Block access to hidden files
location ~ /\. {
deny all;
}
# Cache static assets
location ~* \.(jpg|jpeg|png|gif|ico|css|js|woff2)$ {
expires 1y;
add_header Cache-Control "public, immutable";
}
}
Enable the site:
sudo ln -s /etc/nginx/sites-available/yourdomain.com /etc/nginx/sites-enabled/
sudo nginx -t
sudo systemctl reload nginx
Step 6: Install SSL with Certbot
sudo apt install certbot python3-certbot-nginx -y
sudo certbot --nginx -d yourdomain.com -d www.yourdomain.com
Certbot automatically modifies your Nginx configuration to enable HTTPS and sets up automatic certificate renewal via systemd timer. Verify renewal works:
sudo certbot renew --dry-run
Step 7: Install Redis for Object Caching (Optional but Recommended)
Redis provides persistent object caching that dramatically reduces database queries for WordPress and other PHP applications:
sudo apt install redis-server -y
sudo systemctl enable redis-server
sudo systemctl start redis-server
Verify Redis is running:
redis-cli ping
You should see PONG in response. For WordPress, install the Redis Object Cache plugin and configure it to connect to the local Redis socket for best performance.
Step 8: Verify the Complete Stack
Create a PHP info file to confirm all components are working:
sudo nano /var/www/yourdomain.com/info.php
<?php phpinfo(); ?>
Visit https://yourdomain.com/info.php in your browser. You should see the PHP information page showing PHP 8.2, OPcache enabled, and all installed extensions listed. Delete this file after verification:
sudo rm /var/www/yourdomain.com/info.php
Performance Benchmarking
After setup, benchmark your configuration with Apache Bench to verify performance:
ab -n 1000 -c 50 https://yourdomain.com/
A properly configured LEMP stack on a 2 vCPU / 2 GB RAM VPS should handle 500–2000 requests per second for a cached WordPress homepage, depending on page complexity and caching configuration.
Conclusion
A properly configured LEMP stack is the foundation of a high-performance PHP hosting environment. The combination of Nginx’s efficient connection handling, PHP-FPM’s isolated process pool, OPcache, MariaDB tuning, and Redis object caching creates a server capable of handling significant traffic on modest hardware. If you are looking for a VPS with NVMe storage to get the most out of this stack, explore Ubuntu VPS plans at VPS.DO — provisioned with Ubuntu 22.04 LTS and full root access for complete configuration control.