+91 80401 38000[email protected]24/7 Expert Support
[email protected]Client Portal →
ServerGurus
← All posts
TutorialsHostingLEMPNginxUbuntuSecurity

Production LEMP Stack on Ubuntu 24.04: Nginx, PHP-FPM 8.3, MariaDB, Redis, SSL

By ServerGurus Team23 July 20265 min read
Production LEMP Stack on Ubuntu 24.04: Nginx, PHP-FPM 8.3, MariaDB, Redis, SSL

Introduction

You just spun up a fresh Ubuntu 24.04 VPS. You need a web server that handles real traffic, serves PHP applications fast, caches queries, and runs HTTPS by default. This guide takes you from zero to a production-grade LEMP stack - Nginx, PHP-FPM 8.3, MariaDB, Redis, and automatic SSL via Let's Encrypt. Every command is tested. Every config is ready to copy-paste.

No fluff. No theory. Just a working server by the end of this page.

Prerequisites

  • Ubuntu 24.04 LTS server (fresh install)
  • Root or sudo access
  • A domain name pointed to your server's IP (for SSL)
  • SSH access

First, update your system:

apt update && apt upgrade -y

Step 1: Install Nginx

Nginx ships in Ubuntu's default repos. Install it directly:

apt install nginx -y
systemctl enable nginx --now

Verify it is running:

systemctl status nginx
curl -I http://localhost

You should see HTTP/1.1 200 OK. If your firewall is enabled, allow HTTP and HTTPS:

ufw allow 'Nginx Full'

Step 2: Install PHP-FPM 8.3

Ubuntu 24.04 includes PHP 8.3. Install it with the extensions most applications need:

apt install php8.3-fpm php8.3-cli php8.3-mysql php8.3-curl php8.3-gd \
  php8.3-mbstring php8.3-xml php8.3-zip php8.3-bcmath php8.3-intl \
  php8.3-redis php8.3-opcache -y

Start and enable:

systemctl enable php8.3-fpm --now

PHP-FPM runs as a socket by default at /run/php/php8.3-fpm.sock. Nginx will connect to this socket.

Configure PHP-FPM for Production

Edit /etc/php/8.3/fpm/pool.d/www.conf and set these values:

pm = dynamic
pm.max_children = 50
pm.start_servers = 10
pm.min_spare_servers = 5
pm.max_spare_servers = 30
pm.max_requests = 500

These settings work for a 2-4 GB VPS. Adjust pm.max_children based on your memory: roughly 50 MB per child process.

Then restart:

systemctl restart php8.3-fpm

Step 3: Install MariaDB

MariaDB 10.11 is the default in Ubuntu 24.04:

apt install mariadb-server mariadb-client -y
systemctl enable mariadb --now

Secure the installation:

mysql_secure_installation

Answer yes to all prompts. Set a strong root password.

Create a database and user for your application:

mysql -u root -p
CREATE DATABASE app_db CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
CREATE USER 'app_user'@'localhost' IDENTIFIED BY 'strong-password-here';
GRANT ALL PRIVILEGES ON app_db.* TO 'app_user'@'localhost';
FLUSH PRIVILEGES;
EXIT;

Step 4: Install and Configure Redis

Redis for object caching and session storage:

apt install redis-server -y
systemctl enable redis-server --now

Verify:

redis-cli ping
# Should return PONG

For production, edit /etc/redis/redis.conf:

maxmemory 256mb
maxmemory-policy allkeys-lru

Restart Redis:

systemctl restart redis-server

Step 5: Configure Nginx for PHP

Create a site configuration at /etc/nginx/sites-available/yourdomain.com:

server {
    listen 80;
    server_name yourdomain.com www.yourdomain.com;
    root /var/www/yourdomain.com/public;
    index index.php index.html;

    # PHP handling
    location ~ \.php$ {
        fastcgi_pass unix:/run/php/php8.3-fpm.sock;
        fastcgi_param SCRIPT_FILENAME $realpath_root$fastcgi_script_name;
        include fastcgi_params;
        fastcgi_read_timeout 300;
    }

    # Cache static assets
    location ~* \.(jpg|jpeg|png|gif|ico|css|js|svg|woff2)$ {
        expires 30d;
        add_header Cache-Control "public, immutable";
    }

    # Security: block access to dotfiles
    location ~ /\. {
        deny all;
        access_log off;
        log_not_found off;
    }
}

Enable the site and test:

ln -s /etc/nginx/sites-available/yourdomain.com /etc/nginx/sites-enabled/
rm /etc/nginx/sites-enabled/default
nginx -t
systemctl reload nginx

Create your document root and a test PHP file:

mkdir -p /var/www/yourdomain.com/public
echo '<?php phpinfo(); ?>' > /var/www/yourdomain.com/public/index.php

Visit http://yourdomain.com. You should see the PHP info page. Delete the test file after verifying it works:

rm /var/www/yourdomain.com/public/index.php

Step 6: SSL with Let's Encrypt

Install Certbot:

apt install certbot python3-certbot-nginx -y

Obtain and install the certificate:

certbot --nginx -d yourdomain.com -d www.yourdomain.com

Certbot modifies your Nginx config to add SSL and sets up automatic renewal via a systemd timer. Verify renewal works:

certbot renew --dry-run

Your site is now running HTTPS with auto-renewing certificates.

Step 7: Optimize Nginx for Production

Edit /etc/nginx/nginx.conf and add inside the http block:

# Buffer size tuning
client_body_buffer_size 16k;
client_header_buffer_size 1k;
large_client_header_buffers 4 8k;

# Timeouts
client_body_timeout 12;
client_header_timeout 12;
keepalive_timeout 15;
send_timeout 10;

# Gzip compression
gzip on;
gzip_vary on;
gzip_min_length 1024;
gzip_types text/plain text/css application/json application/javascript text/xml application/xml application/xml+rss text/javascript image/svg+xml;

# Limit requests
limit_req_zone $binary_remote_addr zone=login:10m rate=10r/m;

Reload Nginx:

systemctl reload nginx

Step 8: Install and Configure Fail2Ban

Protect against brute force attacks:

apt install fail2ban -y

Create /etc/fail2ban/jail.local:

[DEFAULT]
bantime = 3600
findtime = 600
maxretry = 5

[sshd]
enabled = true

[nginx-http-auth]
enabled = true

[nginx-botsearch]
enabled = true

Start Fail2Ban:

systemctl enable fail2ban --now

Verification Checklist

Run through these checks before going live:

  1. systemctl status nginx php8.3-fpm mariadb redis-server - all active
  2. curl -I https://yourdomain.com - returns 200 with valid SSL
  3. redis-cli ping - returns PONG
  4. mysql -u app_user -p -e "SELECT 1" - connects successfully
  5. nginx -t - configuration test passes
  6. certbot certificates - shows your certificate with expiry date

What This Stack Handles

This configuration comfortably serves 50-100 concurrent PHP requests on a 2 GB VPS. With Nginx micro-caching, Redis object cache, and MariaDB query cache, most WordPress, Laravel, and custom PHP applications run smoothly.

If you need higher throughput, add more PHP-FPM children (monitor with htop), increase Redis memory, or scale horizontally behind a load balancer.

How ServerGurus Helps

Every ServerGurus cloud VPS ships with Ubuntu 24.04 ready to go. Our bare metal servers give you dedicated CPU, NVMe storage, and unmetered bandwidth - which means this exact stack runs 10x faster than on a shared $5 instance. We also offer managed hosting where our team handles all the steps above for you, including ongoing security updates and monitoring.

Next Steps

  1. Deploy your application code to /var/www/yourdomain.com/public
  2. Set up nightly database backups: mysqldump app_db | gzip > /backup/db-$(date +%F).sql.gz
  3. Monitor resources with htop, iotop, and netdata
  4. Set up log rotation in /etc/logrotate.d/

For a VPS that runs this stack at production speed, check our plans. Need it managed for you? Talk to our team.

Ready to build your infrastructure?

Get a quote from our Hyderabad-based team - Tier IV datacenter, real support, INR or USD billing.

View pricingRequest a quoteWhatsApp sales