Dedicated Servers & VPSJanuary 22, 2026 30 views

How to install Nginx and PHP-FPM on a VPS

How to install Nginx and PHP-FPM on a VPS

Deploying a High-Performance Web Stack: Nginx & PHP 8.2 FPM

This guide will walk you through setting up a robust and secure server environment on a VPS, ideal for hosting modern frameworks like Laravel, Symfony, or CMS such as WordPress.

🎯 Configuration Objectives

  • Web Server: Nginx (high performance for concurrent connections).
  • PHP Engine: PHP 8.2 via FPM (FastCGI Process Manager).
  • Security: HTTPS via Let's Encrypt, UFW firewall, and protection against brute force attacks.
  • Optimization: Static cache and proper access rights management.

📋 Prerequisites

  • A server running Debian 12 or Ubuntu 22.04+.
  • SSH access with sudo privileges.
  • A domain name with an "A" record pointing to your server's IP.

Step 1: Preparation and Nginx Installation

Start by refreshing the package list and installing the web server.

# System update
sudo apt update && sudo apt upgrade -y

# Nginx installation and activation
sudo apt install -y nginx
sudo systemctl enable --now nginx

Firewall Configuration (UFW): Allow web traffic for your site to be accessible.

sudo ufw allow "Nginx Full"

Step 2: PHP 8.2 Installation and Optimization

We are installing PHP 8.2 with essential extensions for most modern applications.

# PHP-FPM installation and common modules
sudo apt install -y php8.2-fpm php8.2-cli php8.2-mysql php8.2-curl \
  php8.2-xml php8.2-gd php8.2-zip php8.2-mbstring php8.2-intl

🔒 Securing PHP

By default, PHP may attempt to execute the nearest file if the exact requested file is not found. Let's disable this risky behavior:

# Disabling cgi.fix_pathinfo
sudo sed -i 's/^\s*;*\s*cgi.fix_pathinfo\s*=.*/cgi.fix_pathinfo=0/' /etc/php/8.2/fpm/php.ini
sudo systemctl restart php8.2-fpm

Step 3: File Structure and Permissions

We will create a dedicated folder for your site and apply restrictive yet functional permissions. Replace my-domain.com with your actual domain.

# Creating directory structure
sudo mkdir -p /var/www/my-domain.com/public

# Granting ownership to web user (www-data)
sudo chown -R www-data:www-data /var/www/my-domain.com

# Securing permissions (Directories to 750, Files to 640)
sudo find /var/www/my-domain.com -type d -exec chmod 750 {} \;
sudo find /var/www/my-domain.com -type f -exec chmod 640 {} \;

Step 4: Nginx Virtual Host Configuration

Create a clean configuration file to instruct Nginx on how to handle requests to your domain.

sudo nano /etc/nginx/sites-available/my-domain.com

Copy this configuration block:

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

    # Handling clean URLs (Laravel/Symfony)
    location / {
        try_files $uri $uri/ /index.php?$query_string;
    }

    # Executing PHP files
    location ~ \.php$ {
        include snippets/fastcgi-php.conf;
        fastcgi_pass unix:/run/php/php8.2-fpm.sock;
    }

    # Optimizing cache for static files
    location ~* \.(?:css|js|jpg|jpeg|gif|png|svg|ico|webp)$ {
        expires 7d;
        access_log off;
        add_header Cache-Control "public";
    }

    # Deny access to hidden files (.env, .git, etc.)
    location ~ /\. {
        deny all;
    }
}

Enable the site:

sudo ln -s /etc/nginx/sites-available/my-domain.com /etc/nginx/sites-enabled/
sudo nginx -t && sudo systemctl reload nginx

Step 5: HTTPS Security (Certbot)

Transitioning to HTTPS is essential today. Let's Encrypt automates this process for free.

sudo apt install -y certbot python3-certbot-nginx
sudo certbot --nginx -d my-domain.com -d www.my-domain.com

Step 6: Maintenance and Advanced Security

🛡️ Protection Against Attacks

Install Fail2ban to automatically ban IPs attempting to force SSH or web access.

sudo apt install -y fail2ban

🔍 Quick Troubleshooting

SymptomProbable CauseAction
502 Bad Gateway ErrorPHP-FPM is stopped or the socket is incorrect.sudo systemctl status php8.2-fpm
403 Forbidden ErrorIncorrect permissions on directories or missing index.Check chown and the /public directory.
Downloaded PHP PageThe location ~ \.php$ block is missing.Check Nginx config and reload.

💡 Variants (RHEL / Rocky Linux Distributions)

If you are on a RedHat base, use dnf. The PHP socket is usually located here: fastcgi_pass unix:/run/php-fpm/www.sock;