Skip to content

Cloud & Server Infrastructure

Configuring a Production LEMP Stack (Linux, Nginx, MariaDB, PHP)

Last reviewed

Summary: A LEMP stack is Linux, Nginx (pronounced 'engine-x'), MariaDB and PHP. Install the three packages from Ubuntu's repositories, secure MariaDB, connect Nginx to PHP-FPM through a Unix socket, then size PHP-FPM's process pool to the RAM you have. Harden the server first with our checklist.

How a LEMP request flows
  1. 01

    Browser

    HTTPS request

  2. 02

    Nginx

    Serves static files directly

  3. 03

    PHP-FPM

    Runs .php via Unix socket

  4. 04

    MariaDB

    Queries over local socket

1. Install the packages

terminalbash
sudo apt update
sudo apt install -y nginx mariadb-server php-fpm php-mysql php-curl php-mbstring php-xml php-zip php-gd php-intl
php -v   # note the version, e.g. 8.3

2. Secure MariaDB

terminalbash
sudo mariadb-secure-installation
sudo mariadb <<'SQL'
CREATE DATABASE app CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
CREATE USER 'app'@'localhost' IDENTIFIED BY 'use-a-long-random-password';
GRANT ALL PRIVILEGES ON app.* TO 'app'@'localhost';
FLUSH PRIVILEGES;
SQL

3. Configure an Nginx server block

/etc/nginx/sites-available/example.canginx
server {
    listen 80;
    listen [::]:80;
    server_name example.ca www.example.ca;
    root /var/www/example.ca/public;
    index index.php index.html;

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

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

    location ~* \.(css|js|png|jpg|webp|svg|woff2)$ {
        expires 30d;
        access_log off;
    }

    location ~ /\. { deny all; }
}
terminalbash
sudo ln -s /etc/nginx/sites-available/example.ca /etc/nginx/sites-enabled/
sudo nginx -t && sudo systemctl reload nginx

4. Tune PHP-FPM workers

Each PHP-FPM child uses memory, often 40–80 MB for a CMS. Measure your real average, then set pm.max_children to roughly (RAM available for PHP ÷ average process size). Setting it too high causes swapping; too low causes queued requests and 502/504 errors.

terminalbash
# Average PHP-FPM process size in MB
ps -ylC php-fpm8.3 --sort:rss | awk 'NR>1 {sum+=$8; n++} END {print sum/n/1024 " MB"}'
/etc/php/8.3/fpm/pool.d/www.conf (2 GB VPS example)ini
pm = dynamic
pm.max_children = 20
pm.start_servers = 4
pm.min_spare_servers = 2
pm.max_spare_servers = 6
pm.max_requests = 500

5. Tune Nginx workers

/etc/nginx/nginx.confnginx
worker_processes auto;
events {
    worker_connections 1024;
}
http {
    gzip on;
    gzip_types text/css application/javascript application/json image/svg+xml;
    client_max_body_size 64m;
}

Finally, add HTTPS with our SSL/TLS guide. If you have not yet secured the server, start with the hardening checklist. More topics live in server infrastructure.

Get new technical guides by email

Occasional, practical server and hosting tutorials for Canadian webmasters. Unsubscribe any time.