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
sudoprivileges. - 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
| Symptom | Probable Cause | Action |
|---|---|---|
| 502 Bad Gateway Error | PHP-FPM is stopped or the socket is incorrect. | sudo systemctl status php8.2-fpm |
| 403 Forbidden Error | Incorrect permissions on directories or missing index. | Check chown and the /public directory. |
| Downloaded PHP Page | The 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;

