PHP-FPM #
PHP-FPM (FastCGI Process Manager) adalah cara modern menjalankan PHP — ia mengelola pool proses PHP yang siap menerima request via protokol FastCGI. Nginx berkomunikasi dengan PHP-FPM melalui Unix socket atau TCP, meneruskan request PHP untuk diproses.
Cara Kerja #
Browser → Nginx → PHP-FPM
│
[PHP worker pool]
worker 1: memproses request A
worker 2: memproses request B
worker 3: idle, menunggu
Nginx menangani semua request — file statis dilayani langsung, hanya request .php yang diteruskan ke PHP-FPM. Ini jauh lebih efisien dari arsitektur Apache + mod_php di mana setiap request memuat interpreter PHP meski hanya untuk file statis.
Konfigurasi Dasar #
server {
listen 80;
server_name example.com;
root /var/www/html;
index index.php index.html;
# File statis — Nginx layani langsung
location ~* \.(css|js|png|jpg|gif|ico|woff2)$ {
expires 30d;
access_log off;
}
# Request utama: coba file, lalu folder, lalu index.php
location / {
try_files $uri $uri/ /index.php?$query_string;
}
# Teruskan request .php ke PHP-FPM
location ~ \.php$ {
# Hindari path traversal: pastikan file benar-benar ada
try_files $uri =404;
fastcgi_pass unix:/run/php/php8.2-fpm.sock;
fastcgi_index index.php;
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
include fastcgi_params;
}
# Blokir akses ke file .htaccess
location ~ /\.ht {
deny all;
}
}
Baris try_files $uri =404 di dalam location PHP sangat penting. Tanpanya, request ke URL seperti /uploads/image.jpg/../../etc/passwd.php bisa diteruskan ke PHP-FPM sebagai path traversal attack. try_files memastikan file PHP benar-benar ada sebelum dieksekusi.
Konfigurasi untuk Laravel / Symfony #
Framework PHP modern menggunakan front controller — semua request diarahkan ke index.php:
server {
listen 443 ssl;
http2 on;
server_name myapp.com;
ssl_certificate /etc/letsencrypt/live/myapp.com/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/myapp.com/privkey.pem;
# Root ke direktori public (bukan root project!)
root /var/www/laravel/public;
index index.php;
# Security: jangan tampilkan direktori
autoindex off;
# Gzip untuk response text
gzip on;
gzip_types text/plain text/css application/json application/javascript;
# Aset statis dengan cache panjang
location ~* \.(css|js|png|jpg|gif|ico|svg|woff2|woff)$ {
expires 1y;
add_header Cache-Control "public, immutable";
access_log off;
try_files $uri =404;
}
# Laravel front controller
location / {
try_files $uri $uri/ /index.php?$query_string;
}
# PHP — teruskan ke FPM
location ~ \.php$ {
try_files $uri =404;
fastcgi_split_path_info ^(.+\.php)(/.+)$;
fastcgi_pass unix:/run/php/php8.2-fpm.sock;
fastcgi_index index.php;
fastcgi_param SCRIPT_FILENAME $realpath_root$fastcgi_script_name;
fastcgi_param PATH_INFO $fastcgi_path_info;
include fastcgi_params;
# Timeout untuk proses PHP yang lama (mis: generate PDF, import CSV)
fastcgi_read_timeout 300;
# Buffer untuk response PHP
fastcgi_buffer_size 32k;
fastcgi_buffers 8 32k;
}
# Blokir akses ke file sensitif
location ~ /\.(ht|git|env) {
deny all;
return 404;
}
# Blokir akses ke direktori vendor dan storage
location ~* ^/(vendor|storage|bootstrap/cache) {
deny all;
return 404;
}
}
FastCGI Cache: Cache Response PHP di Nginx #
Untuk halaman yang tidak berubah per-request (landing page, artikel blog), Nginx bisa menyimpan output PHP di cache — menghindari eksekusi PHP sama sekali untuk request berikutnya:
http {
# Definisikan zone cache FastCGI
fastcgi_cache_path /var/cache/nginx/php
levels=1:2
keys_zone=php_cache:10m
max_size=1g
inactive=60m;
fastcgi_cache_key "$scheme$request_method$host$request_uri";
}
server {
location ~ \.php$ {
try_files $uri =404;
fastcgi_pass unix:/run/php/php8.2-fpm.sock;
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
include fastcgi_params;
fastcgi_cache php_cache;
fastcgi_cache_valid 200 10m;
fastcgi_cache_bypass $cookie_session_id $http_authorization;
fastcgi_no_cache $cookie_session_id $http_authorization;
add_header X-FastCGI-Cache $upstream_cache_status;
}
}
FastCGI cache paling efektif untuk site dengan trafik tinggi dan banyak halaman publik yang kontennya tidak berubah per request.
Tuning PHP-FPM Pool #
Konfigurasi di /etc/php/8.2/fpm/pool.d/www.conf:
[www]
user = www-data
group = www-data
; Unix socket lebih cepat dari TCP loopback
listen = /run/php/php8.2-fpm.sock
listen.owner = www-data
listen.group = www-data
; pm = dynamic: jumlah proses menyesuaikan kebutuhan
pm = dynamic
pm.max_children = 50 ; Batas atas total proses PHP
pm.start_servers = 5 ; Proses yang dibuat saat startup
pm.min_spare_servers = 5 ; Minimum proses idle
pm.max_spare_servers = 10 ; Maksimum proses idle
pm.max_requests = 500 ; Restart proses setelah N request (cegah memory leak)
Untuk menentukan pm.max_children, bagi RAM yang tersedia untuk PHP dengan memory per proses:
# Lihat memory rata-rata per proses PHP
ps aux | grep php-fpm | awk '{print $6}' | sort -n | tail -5
# Misalnya: rata-rata 50MB per proses
# Server dengan 2GB RAM untuk PHP:
# 2048 / 50 = ~40 proses maksimum
Ringkasan #
- Selalu tambahkan
try_files $uri =404di dalam location PHP untuk mencegah path traversal attack.- Untuk Laravel/Symfony, root harus ke direktori
public/, bukan root project.- Unix socket (
unix:/run/php/php8.2-fpm.sock) lebih cepat dari TCP untuk komunikasi Nginx ↔ PHP-FPM di server yang sama.- FastCGI cache bisa drastis mengurangi beban PHP untuk halaman publik yang statis — tambahkan
X-FastCGI-Cacheheader untuk memantau hit rate.- Tuning
pm.max_childrendi PHP-FPM berdasarkan RAM yang tersedia dibagi memory per proses — terlalu tinggi bisa menyebabkan server swap.