Linux VPS

Install a LEMP stack by hand (Nginx, MariaDB, PHP-FPM) on Ubuntu or AlmaLinux

Build a fast LEMP server: install Nginx, MariaDB and PHP-FPM on Ubuntu 24.04 or AlmaLinux 9, write a server block for PHP apps, secure it and add Let's Encrypt SSL.

IntermediateLinux VPS2 min read

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 enable

AlmaLinux:

dnf -y update && dnf -y install nginx
systemctl enable --now nginx
firewall-cmd --permanent --add-service=http --add-service=https && firewall-cmd --reload

More 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-installation

Install 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-curl

AlmaLinux 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-fpm

On 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/public

Create /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 nginx

Add 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 the http block of nginx.conf.
  • Set client_max_body_size to 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_pass socket path is wrong or PHP-FPM is stopped; check ls /run/php* and systemctl status php*-fpm.
  • File not found for PHP files: wrong root or SCRIPT_FILENAME.
  • Permalinks give 404: the try_files line is missing.

Next steps

Was this guide helpful?

Still stuck?

Ask MdmHost AI for a quick answer, or open a ticket and our team will take a look. We are here 24/7.