LEMP replaces Apache with Nginx (pronounced engine-x), which serves static files very efficiently and passes PHP to PHP-FPM. It is a popular choice for VPS hosting of WordPress, Laravel and other PHP apps.
Before you start
- A fresh Ubuntu 24.04 or AlmaLinux 9 VPS with at least 1 GB RAM.
- Root or sudo access, and a domain pointing to the server IP.
- Note: Nginx does not read
.htaccess. Rewrite rules go in the server block.
Prepare and install Nginx
Ubuntu:
apt update && apt -y full-upgrade && apt -y install nginx
ufw allow OpenSSH && ufw allow 'Nginx Full' && ufw enableAlmaLinux:
dnf -y update && dnf -y install nginx
systemctl enable --now nginx
firewall-cmd --permanent --add-service=http --add-service=https && firewall-cmd --reloadMore options: install Nginx on Linux.
Install MariaDB
apt -y install mariadb-server # Ubuntu
dnf -y install mariadb-server # AlmaLinux
systemctl enable --now mariadb
mariadb-secure-installationInstall PHP-FPM
Ubuntu 24.04 (PHP 8.3):
apt -y install php-fpm php-mysql php-gd php-xml php-mbstring php-intl php-zip php-curlAlmaLinux 9:
dnf -y module enable php:8.2
dnf -y install php-fpm php-mysqlnd php-gd php-xml php-mbstring php-intl php-zip php-opcache
systemctl enable --now php-fpmOn AlmaLinux, edit /etc/php-fpm.d/www.conf and set user = nginx and group = nginx, then restart php-fpm.
Create a server block
mkdir -p /var/www/example.com/publicCreate /etc/nginx/sites-available/example.com (Ubuntu) or /etc/nginx/conf.d/example.com.conf (AlmaLinux):
server {
listen 80;
server_name example.com www.example.com;
root /var/www/example.com/public;
index index.php index.html;
location / {
try_files $uri $uri/ /index.php?$args;
}
location ~ \.php$ {
include fastcgi_params;
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
fastcgi_pass unix:/run/php/php8.3-fpm.sock;
}
location ~ /\.(?!well-known) { deny all; }
}On AlmaLinux use fastcgi_pass unix:/run/php-fpm/www.sock;. On Ubuntu enable the site with ln -s /etc/nginx/sites-available/example.com /etc/nginx/sites-enabled/. Then test and reload:
nginx -t && systemctl reload nginxAdd SSL
Issue a free certificate with certbot: Let's Encrypt for Nginx, then redirect HTTP to HTTPS: Nginx HTTPS redirect.
Hardening
- Add
server_tokens off;in thehttpblock ofnginx.conf. - Set
client_max_body_sizeto match PHP's upload limit. - Run automatic security updates and Fail2Ban.
- Tune PHP-FPM workers to your RAM: PHP-FPM pool tuning.
Verify
Create a temporary info.php with <?php phpinfo();, open it, check that PHP runs through FPM, then delete it.
Troubleshooting
- 502 Bad Gateway: the
fastcgi_passsocket path is wrong or PHP-FPM is stopped; checkls /run/php*andsystemctl status php*-fpm. - File not found for PHP files: wrong
rootorSCRIPT_FILENAME. - Permalinks give 404: the
try_filesline is missing.
