Introduction
Nginx (pronounced "engine-x") is a high-performance web server, known for its speed, stability, and low resource consumption. Combined with PHP-FPM (FastCGI Process Manager), it forms a powerful stack for hosting modern PHP applications like WordPress, Laravel, Symfony, or Drupal.
Why Choose Nginx + PHP-FPM?
| Feature | Apache + mod_php | Nginx + PHP-FPM |
|---|---|---|
| Memory | High consumption | Low footprint |
| Simultaneous Connections | Limited | Thousands |
| Static Files | Good | Excellent |
| Configuration | Distributed .htaccess | Centralized |
| Performance | Good | Excellent |
Versions Included per OS
| System | Nginx | PHP | Kernel |
|---|---|---|---|
| Debian 13 "Trixie" | 1.26 | 8.4 | 6.12 LTS |
| Ubuntu 24.04 LTS | 1.24 | 8.3 | 6.8 |
📋 Prerequisites
- A VPS with Ubuntu 24.04 LTS or Debian 13 "Trixie"
- Root access or user with sudo privileges
- Established SSH connection
- Domain name pointing to the VPS IP (optional but recommended)
🔄 Step 1: System Update
Before any installation, update the system packages:
sudo apt update && sudo apt upgrade -y
If a reboot is required:
[ -f /var/run/reboot-required ] && sudo reboot
📦 Step 2: Install Nginx
Installation
sudo apt install nginx -y
Verify the Installation
nginx -v
Expected Output:
- Debian 13:
nginx version: nginx/1.26.x - Ubuntu 24.04:
nginx version: nginx/1.24.x
Check Service Status
sudo systemctl status nginx
The service should display active (running).
Nginx Management Commands
| Action | Command |
|---|---|
| Start | sudo systemctl start nginx |
| Stop | sudo systemctl stop nginx |
| Restart | sudo systemctl restart nginx |
| Reload config | sudo systemctl reload nginx |
| Enable at boot | sudo systemctl enable nginx |
| Disable at boot | sudo systemctl disable nginx |
| Test configuration | sudo nginx -t |
Configure Firewall (UFW)
If UFW is active, allow HTTP and HTTPS traffic:
# Check UFW status
sudo ufw status
# Allow Nginx (HTTP + HTTPS)
sudo ufw allow 'Nginx Full'
# Or allow separately
sudo ufw allow 80/tcp
sudo ufw allow 443/tcp
Test the Installation
Open your browser and access http://YOUR_VPS_IP. You should see the Nginx welcome page with "Welcome to nginx!" message.
🐘 Step 3: Install PHP-FPM
For Debian 13 "Trixie" (PHP 8.4)
sudo apt install php8.4-fpm php8.4-cli php8.4-common php8.4-mysql \
php8.4-zip php8.4-gd php8.4-mbstring php8.4-curl php8.4-xml \
php8.4-bcmath php8.4-intl php8.4-soap php8.4-opcache php8.4-readline -y
For Ubuntu 24.04 LTS (PHP 8.3)
sudo apt install php8.3-fpm php8.3-cli php8.3-common php8.3-mysql \
php8.3-zip php8.3-gd php8.3-mbstring php8.3-curl php8.3-xml \
php8.3-bcmath php8.3-intl php8.3-soap php8.3-opcache php8.3-readline -y
Install Specific Version via PPA (Ubuntu Only)
If you need a different PHP version on Ubuntu:
# Add Ondřej PPA repository
sudo apt install software-properties-common -y
sudo add-apt-repository ppa:ondrej/php -y
sudo apt update
# Example: Install PHP 8.4
sudo apt install php8.4-fpm php8.4-cli php8.4-common php8.4-mysql \
php8.4-zip php8.4-gd php8.4-mbstring php8.4-curl php8.4-xml \
php8.4-bcmath php8.4-intl php8.4-soap php8.4-opcache -y
Verify PHP Installation
php -v
Expected Output:
- Debian 13:
PHP 8.4.x (cli) - Ubuntu 24.04:
PHP 8.3.x (cli)
Check PHP-FPM Status
Debian 13:
sudo systemctl status php8.4-fpm
Ubuntu 24.04:
sudo systemctl status php8.3-fpm
The service should display active (running).
Identify PHP-FPM Socket
The socket is crucial for communication between Nginx and PHP:
ls /run/php/
Typical Output:
- Debian 13:
php8.4-fpm.sock - Ubuntu 24.04:
php8.3-fpm.sock
⚙️ Step 4: Configure Nginx for PHP-FPM
Modify Default Configuration
Edit the default configuration file:
sudo nano /etc/nginx/sites-available/default
Configuration for Debian 13 (PHP 8.4)
server {
listen 80 default_server;
listen [::]:80 default_server;
root /var/www/html;
index index.php index.html index.htm;
server_name _;
location / {
try_files $uri $uri/ =404;
}
# PHP-FPM Configuration
location ~ \.php$ {
include snippets/fastcgi-php.conf;
fastcgi_pass unix:/run/php/php8.4-fpm.sock;
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
include fastcgi_params;
}
# Block access to .htaccess files
location ~ /\.ht {
deny all;
}
}
Configuration for Ubuntu 24.04 (PHP 8.3)
server {
listen 80 default_server;
listen [::]:80 default_server;
root /var/www/html;
index index.php index.html index.htm;
server_name _;
location / {
try_files $uri $uri/ =404;
}
# PHP-FPM Configuration
location ~ \.php$ {
include snippets/fastcgi-php.conf;
fastcgi_pass unix:/run/php/php8.3-fpm.sock;
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
include fastcgi_params;
}
# Block access to .htaccess files
location ~ /\.ht {
deny all;
}
}
Test the Configuration
sudo nginx -t
Expected Output:
nginx: the configuration file /etc/nginx/nginx.conf syntax is ok
nginx: configuration file /etc/nginx/nginx.conf test is successful
Reload Nginx
sudo systemctl reload nginx
✅ Step 5: Test PHP with Nginx
Create a PHP Test File
echo "<?php phpinfo(); ?>" | sudo tee /var/www/html/info.php
Access the Test Page
Open your browser: http://YOUR_IP_VPS/info.php
You should see the phpinfo() page displaying:
- PHP Version (8.4.x or 8.3.x)
- Server API: FPM/FastCGI
- Installed Extensions
- Configuration Variables
Delete the Test File (Security)
sudo rm /var/www/html/info.php
⚠️ Security: Never leave a
phpinfo()file in production, as it exposes sensitive information.
🌐 Step 6: Create a Virtual Host (Server Block)
Virtual hosts allow hosting multiple sites on the same server.
Create Site Directory
sudo mkdir -p /var/www/monsite.com/html
sudo chown -R $USER:$USER /var/www/monsite.com
sudo chmod -R 755 /var/www/monsite.com
Create Homepage
nano /var/www/monsite.com/html/index.php
Add:
<!DOCTYPE html>
<html lang="fr">
<head>
<meta charset="UTF-8">
<title>Welcome to MonSite.com</title>
<style>
body { font-family: Arial, sans-serif; text-align: center; padding: 50px; }
h1 { color: #333; }
</style>
</head>
<body>
<h1>MonSite.com is working!</h1>
<p>Nginx + PHP-FPM configured successfully.</p>
<p>PHP Version: <?php echo phpversion(); ?></p>
</body>
</html>
Create Virtual Host Configuration
sudo nano /etc/nginx/sites-available/monsite.com
For Debian 13 (PHP 8.4):
server {
listen 80;
listen [::]:80;
server_name monsite.com www.monsite.com;
root /var/www/monsite.com/html;
index index.php index.html index.htm;
# Logs
access_log /var/log/nginx/monsite.com.access.log;
error_log /var/log/nginx/monsite.com.error.log;
location / {
try_files $uri $uri/ /index.php?$query_string;
}
# PHP-FPM
location ~ \.php$ {
include snippets/fastcgi-php.conf;
fastcgi_pass unix:/run/php/php8.4-fpm.sock;
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
include fastcgi_params;
}
# Security - block hidden files
location ~ /\. {
deny all;
}
# Cache for static files
location ~* \.(jpg|jpeg|png|gif|ico|css|js|pdf|txt|woff|woff2|ttf|svg)$ {
expires 30d;
add_header Cache-Control "public, no-transform";
}
}
For Ubuntu 24.04 (PHP 8.3): Replace php8.4-fpm.sock with php8.3-fpm.sock.
Enable the Virtual Host
sudo ln -s /etc/nginx/sites-available/monsite.com /etc/nginx/sites-enabled/
Disable Default Site (Optional)
sudo rm /etc/nginx/sites-enabled/default
Test and Reload
sudo nginx -t
sudo systemctl reload nginx
🔒 Step 7: Install an SSL Certificate (Let's Encrypt)
Install Certbot
sudo apt install certbot python3-certbot-nginx -y
Obtain an SSL Certificate
sudo certbot --nginx -d monsite.com -d www.monsite.com
Follow the instructions:
- Enter your email address
- Agree to the terms
- Choose to redirect HTTP to HTTPS (recommended)
Check Automatic Renewal
sudo certbot renew --dry-run
⚡ Step 8: Optimize PHP-FPM
PHP-FPM Pool Configuration
Debian 13:
sudo nano /etc/php/8.4/fpm/pool.d/www.conf
Ubuntu 24.04:
sudo nano /etc/php/8.3/fpm/pool.d/www.conf
Recommended Parameters based on RAM
VPS 1-2 GB RAM:
pm = dynamic
pm.max_children = 10
pm.start_servers = 2
pm.min_spare_servers = 1
pm.max_spare_servers = 3
pm.max_requests = 500
VPS 4 GB RAM:
pm = dynamic
pm.max_children = 25
pm.start_servers = 5
pm.min_spare_servers = 3
pm.max_spare_servers = 10
pm.max_requests = 1000
VPS 8+ GB RAM:
pm = dynamic
pm.max_children = 50
pm.start_servers = 10
pm.min_spare_servers = 5
pm.max_spare_servers = 20
pm.max_requests = 2000
user www-data;
worker_processes auto;
pid /run/nginx.pid;
include /etc/nginx/modules-enabled/*.conf;
events {
worker_connections 1024;
multi_accept on;
use epoll;
}
http {
# Basic settings
sendfile on;
tcp_nopush on;
tcp_nodelay on;
keepalive_timeout 65;
types_hash_max_size 2048;
server_tokens off;
# Buffer sizes
client_max_body_size 64M;
client_body_buffer_size 128k;
# MIME types
include /etc/nginx/mime.types;
default_type application/octet-stream;
# Logging
access_log /var/log/nginx/access.log;
error_log /var/log/nginx/error.log;
# Gzip compression
gzip on;
gzip_vary on;
gzip_proxied any;
gzip_comp_level 6;
gzip_types text/plain text/css text/xml application/json application/javascript
application/rss+xml application/atom+xml image/svg+xml;
# Includes
include /etc/nginx/conf.d/*.conf;
include /etc/nginx/sites-enabled/*;
}
Restart Nginx
sudo nginx -t
sudo systemctl restart nginx
🛡️ Step 10: Secure the Installation
Security Headers
sudo nginx -t
sudo systemctl restart nginx
Add in your server block configuration:
# Security Headers
add_header X-Frame-Options "SAMEORIGIN" always;
add_header X-Content-Type-Options "nosniff" always;
add_header X-XSS-Protection "1; mode=block" always;
add_header Referrer-Policy "strict-origin-when-cross-origin" always;
add_header Permissions-Policy "geolocation=(), microphone=(), camera=()" always;
Limit Requests (Rate Limiting)
In /etc/nginx/nginx.conf, http section:
# Limiting zones
limit_req_zone $binary_remote_addr zone=one:10m rate=10r/s;
limit_conn_zone $binary_remote_addr zone=addr:10m;
In your server block:
location / {
limit_req zone=one burst=20 nodelay;
limit_conn addr 10;
}
📁 File Structure
Nginx
| Path | Description |
|---|---|
/etc/nginx/nginx.conf | Main configuration |
/etc/nginx/sites-available/ | Available configurations |
/etc/nginx/sites-enabled/ | Active configurations (symbolic links) |
/etc/nginx/snippets/ | Configuration snippets |
/var/log/nginx/ | Access and error logs |
PHP-FPM
| Path (Debian 13) | Path (Ubuntu 24.04) | Description |
|---|---|---|
/etc/php/8.4/fpm/php.ini | /etc/php/8.3/fpm/php.ini | PHP configuration |
/etc/php/8.4/fpm/pool.d/www.conf | /etc/php/8.3/fpm/pool.d/www.conf | Pool configuration |
/run/php/php8.4-fpm.sock | /run/php/php8.3-fpm.sock | FPM socket |
Websites
| Path | Description |
|---|---|
/var/www/html/ | Default site |
/var/www/monsite.com/html/ | Root of a custom site |
🔧 Useful Commands
Service Management
# Nginx
sudo systemctl start|stop|restart|reload|status nginx
# PHP-FPM (Debian 13)
sudo systemctl start|stop|restart|status php8.4-fpm
# PHP-FPM (Ubuntu 24.04)
sudo systemctl start|stop|restart|status php8.3-fpm
Tests and Diagnostics
# Test Nginx config
sudo nginx -t
# Test PHP-FPM config (Debian 13)
sudo php-fpm8.4 -t
# Test PHP-FPM config (Ubuntu 24.04)
sudo php-fpm8.3 -t
# View PHP-FPM processes
ps aux | grep php-fpm
# View active connections
ss -tlnp | grep -E 'nginx|php'
# Real-time logs
sudo tail -f /var/log/nginx/error.log
Site Management
# Enable a site
sudo ln -s /etc/nginx/sites-available/monsite.com /etc/nginx/sites-enabled/
# Disable a site
sudo rm /etc/nginx/sites-enabled/monsite.com
# List active sites
ls -la /etc/nginx/sites-enabled/
🔍 Troubleshooting
"502 Bad Gateway"
Causes: PHP-FPM not working or incorrect socket
Solutions:
# Check PHP-FPM (adjust version)
sudo systemctl status php8.4-fpm
# Check the socket
ls -la /run/php/
# Restart PHP-FPM
sudo systemctl restart php8.4-fpm
"403 Forbidden"
Causes: Incorrect permissions
Solutions:
# Correct permissions
sudo chown -R www-data:www-data /var/www/monsite.com
sudo chmod -R 755 /var/www/monsite.com
"404 Not Found" for PHP files
Causes: Incorrect PHP-FPM configuration
Checks:
- The file exists
- The
rootdirective is correct in Nginx - The
location ~ \.php$block is present - The socket matches the installed PHP version
Blank Page (PHP not executing)
Causes: PHP-FPM not connected to Nginx
Solutions:
# Check socket version
ls /run/php/
# Compare with Nginx config
grep fastcgi_pass /etc/nginx/sites-enabled/*
📋 Quick Recap
Complete Installation Debian 13
# Update
sudo apt update && sudo apt upgrade -y
# Nginx
sudo apt install nginx -y
# PHP-FPM 8.4
sudo apt install php8.4-fpm php8.4-cli php8.4-common php8.4-mysql \
php8.4-zip php8.4-gd php8.4-mbstring php8.4-curl php8.4-xml \
php8.4-bcmath php8.4-intl php8.4-opcache -y
# Firewall
sudo ufw allow 'Nginx Full'
# SSL
sudo apt install certbot python3-certbot-nginx -y
Complete Installation Ubuntu 24.04
# Update
sudo apt update && sudo apt upgrade -y
# Nginx
sudo apt install nginx -y
# PHP-FPM 8.3
sudo apt install php8.3-fpm php8.3-cli php8.3-common php8.3-mysql \
php8.3-zip php8.3-gd php8.3-mbstring php8.3-curl php8.3-xml \
php8.3-bcmath php8.3-intl php8.3-opcache -y
# Firewall
sudo ufw allow 'Nginx Full'
# SSL
sudo apt install certbot python3-certbot-nginx -y
💡 Best Practices
-
Always test the configuration before reloading:
sudo nginx -t -
Use separate virtual hosts for each site
-
Enable HTTPS with Let's Encrypt for all sites
-
Regularly monitor logs to detect issues
-
Backup your configurations before making changes
-
Optimize PHP-FPM according to your VPS resources
-
Regularly update Nginx and PHP for security
-
Remove test files (info.php) after verification


