PHP-FPM (Laravel/WordPress) #
Berbeda dengan Node.js atau Go yang bertindak sebagai server HTTP mandiri, runtime PHP (seperti PHP 8.x) tidak dirancang untuk menerima koneksi HTTP secara langsung dari internet. PHP membutuhkan web server eksternal sebagai gerbang depan untuk menerima permintaan masuk, mengelola lalu lintas statis, dan meneruskan permintaan dinamis PHP ke interpreter.
Pada era web modern, kombinasi Nginx dan PHP-FPM (FastCGI Process Manager) adalah standar emas industri untuk menjalankan aplikasi PHP tingkat produksi (seperti Laravel, Symfony, atau WordPress). PHP-FPM mengelola sekumpulan proses worker (worker pools) secara dinamis untuk mengeksekusi skrip PHP secara paralel. Di artikel ini, kita akan membahas perbandingan protokol FastCGI, membedah performa Unix vs TCP socket, menyusun pola routing pretty URLs untuk framework MVC, menerapkan pengerasan keamanan (security hardening) folder unggahan, serta menyusun konfigurasi produksi siap pakai untuk Laravel dan WordPress.
Arsitektur Alur Komunikasi FastCGI #
Nginx berkomunikasi dengan PHP-FPM menggunakan protokol FastCGI, sebuah protokol biner berkinerja tinggi yang dirancang khusus untuk menjembatani server web dengan aplikasi eksternal.
Berikut adalah diagram alur keputusan dan pemrosesan permintaan PHP di Nginx:
flowchart TD
Klien["Klien Browser"] -->|"HTTP Request"| Nginx["Nginx Web Server"]
Nginx -->|"Cek File Statik di Disk"| StaticCheck{"Apakah File Statik?"}
StaticCheck -->|"Ya: JS/CSS/Images"| ServeStatic["Sajikan Langsung dari Disk"]
StaticCheck -->|"Tidak: File .php"| FastCGI["Terjemahkan ke Protokol FastCGI"]
FastCGI -->|"Pilih Socket"| SocketCheck{"Tipe Socket?"}
SocketCheck -->|"Unix Socket (Cepat, Satu Mesin)"| UnixSock["unix:/run/php/php8.2-fpm.sock"]
SocketCheck -->|"TCP Socket (Skalabel, Multi Server)"| TCPSock["127.0.0.1:9000"]
UnixSock --> PHPMaster["PHP-FPM Master Process"]
TCPSock --> PHPMaster
PHPMaster -->|"Dikelola secara Dinamis"| PHPWorker["PHP-FPM Worker Process"]
PHPWorker -->|"Eksekusi Script PHP"| AppCode["Aplikasi PHP (Laravel / WordPress)"]
AppCode -->|"Respons Data"| PHPWorker
PHPWorker --> Nginx
Nginx -->|"Kembalikan HTTP Response"| Klien
classDef default fill:#f9f9f9,stroke:#d1d5db,stroke-width:1px,color:#111827;
classDef nginxStyle fill:#eff6ff,stroke:#3b82f6,stroke-width:2px,color:#1e3a8a;
classDef phpStyle fill:#f5f3ff,stroke:#7c3aed,stroke-width:2px,color:#5b21b6;
class Nginx,ServeStatic,FastCGI nginxStyle;
class PHPMaster,PHPWorker,AppCode phpStyle;HTTP (Reverse Proxy) vs FastCGI Protocol #
Saat Nginx bertindak sebagai reverse proxy untuk Node.js, protokol yang digunakan dari awal hingga akhir adalah HTTP. Namun, saat berkomunikasi dengan PHP-FPM, Nginx bertindak sebagai klien FastCGI. Nginx akan:
- Menerjemahkan request HTTP klien (header, metode, query string, cookie) menjadi format paket biner FastCGI.
- Mengirimkan paket biner tersebut ke socket PHP-FPM.
- PHP-FPM menerima paket, memanggil berkas
.phpyang diminta, mengeksekusinya di salah satu proses worker, dan mengembalikan respons mentah ke Nginx. - Nginx merangkum kembali respons mentah tersebut menjadi respons HTTP standar dan mengirimkannya ke browser klien.
Pemecahan peran ini membuat Nginx sangat fokus menangani koneksi jaringan dan penyajian aset statik yang cepat, sementara proses PHP-FPM murni fokus mengeksekusi logika skrip tanpa terganggu beban overhead protokol jaringan luar.
Perbandingan Socket: Unix Socket vs TCP Socket #
Nginx dan PHP-FPM dapat dihubungkan melalui dua tipe soket: Unix Domain Socket atau TCP/IP Socket. Kita harus memilih tipe soket yang paling sesuai dengan arsitektur infrastruktur server kita.
1. Unix Domain Socket #
Unix socket direpresentasikan sebagai berkas fisik di dalam sistem operasi (misalnya /run/php/php8.2-fpm.sock).
- Performa: Sangat Cepat. Komunikasi terjadi langsung di dalam kernel memori tanpa melalui tumpukan protokol jaringan (network stack). Langkah ini meniadakan latensi loopback lokal dan pemrosesan header paket TCP internal.
- Keterbatasan: Nginx dan PHP-FPM harus berada di dalam satu mesin server fisik yang sama.
- Snippet Konfigurasi Nginx:
fastcgi_pass unix:/run/php/php8.2-fpm.sock;
2. TCP/IP Socket #
TCP socket menggunakan alamat IP dan nomor port (misalnya 127.0.0.1:9000).
- Performa: Sedikit lebih lambat jika berjalan di satu mesin yang sama karena ada beban overhead routing jaringan lokal (loopback network stack).
- Skalabilitas: Sangat Tinggi. Kita bisa memisahkan server Nginx di satu mesin terdepan, dan menaruh PHP-FPM di beberapa server backend terpisah guna meningkatkan kapasitas komputasi (scale-out).
- Snippet Konfigurasi Nginx:
fastcgi_pass 127.0.0.1:9000;
Pola Routing Pretty URLs untuk MVC Framework #
Aplikasi MVC modern (seperti Laravel) hanya memiliki satu berkas pintu masuk utama, yaitu /public/index.html atau /public/index.php. Seluruh alamat URL (seperti /profile, /api/users) tidak mewakili folder fisik asli di disk server, melainkan diatur secara dinamis oleh router internal PHP.
Jika klien meminta URL /blog/read-post, Nginx harus memeriksa apakah file tersebut ada di disk. Jika tidak ada, Nginx harus menulis ulang URL tersebut secara internal dan meneruskannya ke index.php.
Kita mengimplementasikan ini menggunakan direktif try_files:
server {
listen 80;
server_name app.unisbadri.com;
root /var/www/my-laravel-app/public;
index index.php;
location / {
# 1. Cek apakah URI berupa berkas fisik ($uri) di disk
# 2. Cek apakah URI berupa folder fisik ($uri/) di disk
# 3. Jika tidak ada, tulis ulang request ke index.php beserta query string asli
try_files $uri $uri/ /index.php?$query_string;
}
location ~ \.php$ {
# Teruskan file .php ke FastCGI interpreter
include fastcgi_params;
fastcgi_pass unix:/run/php/php8.2-fpm.sock;
# Beritahu PHP-FPM lokasi absolut file script yang harus dijalankan
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
}
}
Pengerasan Keamanan: Blokir Eksekusi PHP di Folder Unggahan #
Salah satu celah kerentanan keamanan paling fatal pada situs web berbasis PHP (terutama WordPress) adalah eksekusi webshell/backdoor di folder unggahan.
Jika aplikasi kita mengizinkan pengguna mengunggah gambar profil, dan penyerang berhasil mengelabui sistem validasi dengan mengunggah berkas berbahaya bernama backdoor.php ke folder publik (misalnya /storage/uploads/ atau /wp-content/uploads/), penyerang tersebut dapat mengeksekusi perintah shell kontrol server kita hanya dengan mengakses URL https://domain.com/uploads/backdoor.php di browser mereka.
Kita wajib menutup celah ini secara permanen di tingkat konfigurasi Nginx dengan memblokir eksekusi modul FastCGI pada folder-folder writeable:
server {
listen 80;
server_name myapp.unisbadri.com;
root /var/www/my-laravel-app/public;
# 1. Blokir eksekusi file PHP di folder penyimpanan Laravel
location ~* ^/storage/uploads/.*\.php$ {
deny all; # Tolak akses instan (403 Forbidden)
}
# 2. Blokir eksekusi file PHP di folder unggahan WordPress
location ~* ^/wp-content/uploads/.*\.php$ {
deny all;
}
location / {
try_files $uri $uri/ /index.php?$query_string;
}
location ~ \.php$ {
include fastcgi_params;
fastcgi_pass unix:/run/php/php8.2-fpm.sock;
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
}
}
Tuning Parameter FastCGI Buffers dan Timeouts #
Untuk memproses aplikasi PHP secara stabil di bawah beban trafik padat, kita harus melakukan fine-tuning pada pengaturan buffer dan batas waktu FastCGI.
1. FastCGI Buffering #
Secara default, Nginx akan menyimpan respons dinamis dari PHP-FPM di memori RAM internal (buffer) sebelum mengirimkannya secara bertahap ke klien. Jika respons PHP (seperti export CSV besar atau data JSON panjang) melebihi kapasitas buffer, Nginx akan menulis data tersebut ke file temporer di disk, yang memicu penurunan performa I/O.
Kita menyetel buffer memori yang cukup longgar di blok http atau server:
# Ukuran buffer untuk menampung header respons pertama
fastcgi_buffer_size 32k;
# 16 buffer berukuran 16KB untuk menampung body respons (total 256KB)
fastcgi_buffers 16 16k;
# Batas memori maksimum saat buffering sibuk sebelum menulis ke disk
fastcgi_busy_buffers_size 64k;
2. FastCGI Timeouts #
Jika skrip PHP kita membutuhkan waktu lama untuk memproses kalkulasi berat (seperti pembuatan laporan PDF atau integrasi API pihak ketiga), PHP-FPM mungkin membutuhkan waktu lebih dari 60 detik (default limit). Jika limit terlampaui, Nginx akan memutus koneksi dan mengembalikan galat 504 Gateway Timeout.
# Batas waktu Nginx menunggu PHP-FPM selesai memproses skrip
fastcgi_read_timeout 180s;
# Batas waktu mengirim data ke PHP-FPM
fastcgi_send_timeout 180s;
Contoh Konfigurasi Server Block Produksi Lengkap #
1. Template Konfigurasi Produksi Laravel (HTTPS + SSL) #
server {
listen 80;
server_name laravel.unisbadri.com;
return 301 https://$host$request_uri;
}
server {
listen 443 ssl http2;
server_name laravel.unisbadri.com;
root /var/www/laravel-app/public;
index index.php;
# Setelan Sertifikat SSL
ssl_certificate /etc/letsencrypt/live/laravel.unisbadri.com/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/laravel.unisbadri.com/privkey.pem;
ssl_protocols TLSv1.2 TLSv1.3;
# Hardening: Blokir akses ke file konfigurasi sensitif (.git, .env)
location ~ /\.(?!well-known).* {
deny all;
}
# Hardening: Blokir eksekusi berkas PHP di folder penyimpanan public uploads
location ~* ^/storage/.*\.php$ {
deny all;
}
location / {
try_files $uri $uri/ /index.php?$query_string;
}
# Offload Aset Statik Laravel
location ~* \.(js|css|png|jpg|jpeg|gif|ico|svg|woff|woff2|webp)$ {
expires 1y;
add_header Cache-Control "public, immutable";
access_log off;
}
# Pemrosesan Skrip PHP FastCGI
location ~ \.php$ {
try_files $uri =404;
include fastcgi_params;
fastcgi_pass unix:/run/php/php8.2-fpm.sock;
fastcgi_index index.php;
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
# Tuning Buffers & Timeouts
fastcgi_buffer_size 32k;
fastcgi_buffers 16 16k;
fastcgi_read_timeout 120s;
# Keamanan tambahan untuk header FastCGI
fastcgi_hide_header X-Powered-By;
}
}
2. Template Konfigurasi Produksi WordPress (HTTPS + SSL) #
WordPress memiliki struktur yang unik karena mengizinkan penulisan berkas dinamis secara langsung di disk (plugin/theme installations). Berikut adalah konfigurasi aman siap pakai:
server {
listen 80;
server_name wp.unisbadri.com;
return 301 https://$host$request_uri;
}
server {
listen 443 ssl http2;
server_name wp.unisbadri.com;
root /var/www/wordpress;
index index.php;
ssl_certificate /etc/letsencrypt/live/wp.unisbadri.com/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/wp.unisbadri.com/privkey.pem;
ssl_protocols TLSv1.2 TLSv1.3;
# Hardening: Blokir akses langsung ke file php internal WordPress
location ~* ^/wp-content/uploads/.*\.php$ {
deny all;
}
# Hardening: Blokir berkas xmlrpc.php (sering jadi target serangan brute force)
location = /xmlrpc.php {
deny all;
access_log off;
log_not_found off;
}
# Hardening: Blokir akses ke wp-config.php kustom kita
location = /wp-config.php {
deny all;
}
# Aturan rewrite pretty URLs WordPress
location / {
try_files $uri $uri/ /index.php?$args;
}
# Caching untuk file statis WordPress
location ~* \.(js|css|png|jpg|jpeg|gif|ico|svg|woff2|webp)$ {
expires 30d;
add_header Cache-Control "public, no-transform";
access_log off;
}
# Pemrosesan PHP WordPress
location ~ \.php$ {
try_files $uri =404;
include fastcgi_params;
fastcgi_pass unix:/run/php/php8.2-fpm.sock;
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
# Tuning FastCGI parameter
fastcgi_buffer_size 32k;
fastcgi_buffers 16 16k;
fastcgi_read_timeout 180s;
# Hide teknologi info
fastcgi_hide_header X-Powered-By;
}
}
Tuning Parameter Process Manager PHP-FPM (www.conf) #
Selain mengonfigurasi Nginx, kita juga harus menyelaraskan konfigurasi pool PHP-FPM (biasanya terletak di /etc/php/8.2/fpm/pool.d/www.conf) agar mampu menangani volume request yang dikirimkan oleh Nginx tanpa menimbulkan galat 502 Bad Gateway atau 504 Gateway Timeout.
Secara default, PHP-FPM menggunakan mode dynamic yang membatasi jumlah proses worker secara moderat. Untuk server dengan trafik tinggi, kita memiliki tiga jenis strategi pengelolaan proses (process manager / pm):
1. Mode static
#
Seluruh proses worker dibuat sejak awal dan dipertahankan aktif di memori tanpa mempedulikan status request.
- Kelebihan: Sangat responsif karena tidak ada overhead pembuatan atau penghancuran proses worker baru secara dinamis.
- Kekurangan: Memakan RAM secara konstan. Cocok untuk server dedicated yang murni menjalankan PHP-FPM.
2. Mode dynamic
#
Jumlah worker naik-turun secara dinamis di antara rentang batas minimum dan maksimum berdasarkan volume request.
- Kelebihan: Menghemat memori RAM saat server sedang sepi pengunjung.
- Kekurangan: Menimbulkan overhead CPU saat memanggil/membuat proses worker baru ketika trafik melonjak tiba-tiba.
3. Mode ondemand
#
Tidak ada worker yang berjalan jika tidak ada request masuk. Worker baru akan dipanggil tepat ketika ada request tiba di socket.
- Kelebihan: Sangat hemat RAM, cocok untuk server development atau shared hosting dengan ratusan web kecil yang jarang diakses.
- Kekurangan: Menambah latensi pada request pertama karena harus menunggu pembuatan proses worker (cold start).
Rumus Menghitung Batas Maksimum Worker (pm.max_children)
#
Jika kita memilih mode static atau dynamic, parameter terpenting yang wajib disesuaikan adalah pm.max_children. Menetapkan angka terlalu tinggi dapat membuat server kehabisan RAM dan crash (OOM Killer), sedangkan terlalu rendah akan memicu error 502 Bad Gateway akibat antrean socket upstream penuh.
Kita dapat menghitungnya menggunakan rumus sederhana berikut: [\text{pm.max_children} = \frac{\text{Total RAM yang dialokasikan untuk PHP-FPM}}{\text{Rata-rata penggunaan RAM per proses PHP Worker}}]
Langkah 1: Periksa rata-rata memori yang dikonsumsi oleh satu proses worker PHP-FPM aktif:
ps aux | grep php-fpm | awk '{print $6}' | awk '{sum+=$1; count++} END {print sum/count/1024 " MB"}' # Misal hasilnya: 45 MB per workerLangkah 2: Tentukan alokasi RAM. Misal server kita memiliki RAM 8 GB, dan kita ingin mengalokasikan 5 GB (5120 MB) khusus untuk memproses skrip PHP (sisa RAM 3 GB digunakan untuk sistem operasi, Nginx, dan database): [\text{pm.max_children} = \frac{5120\text{ MB}}{45\text{ MB}} \approx 113]
Langkah 3: Terapkan konfigurasi tersebut di
/etc/php/8.2/fpm/pool.d/www.conf:pm = dynamic pm.max_children = 110 pm.start_servers = 15 pm.min_spare_servers = 10 pm.max_spare_servers = 30 pm.max_requests = 1000(Tip: Direktif
pm.max_requests = 1000memaksa proses worker untuk merestart dirinya sendiri setelah melayani 1000 request. Ini berguna untuk membersihkan akumulasi kebocoran memori (memory leak) di runtime aplikasi PHP).
Setelah melakukan modifikasi di file konfigurasi PHP-FPM, kita wajib merestart layanan PHP-FPM agar konfigurasi baru diterapkan:
sudo systemctl restart php8.2-fpm
Ringkasan dan Praktik Terbaik #
- Pilih Unix Socket untuk Server Tunggal: Jika Nginx dan PHP-FPM kita berjalan berdampingan pada satu server fisik yang sama, selalu gunakan Unix Domain Socket demi performa transfer memori yang paling cepat.
- Amankan Folder Uploads Secara Agresif: Jangan pernah melewatkan konfigurasi
deny alluntuk file PHP di dalam direktori penyimpanan yang bisa ditulisi pengguna guna menangkal ancaman eksploitasi webshell/backdoor.- Gunakan try_files $uri =404: Pada location block PHP, selalu sertakan
try_files $uri =404;sebelum memanggilfastcgi_pass. Hal ini mencegah Nginx mengirimkan file kosong ke PHP-FPM yang dapat memicu serangan bertipe arbitrary code execution.- Sembunyikan X-Powered-By: PHP secara default mengirimkan header
X-Powered-By: PHP/8.x. Gunakan direktiffastcgi_hide_header X-Powered-By;untuk menyembunyikan informasi teknologi server kita dari pemindaian bot penyerang.
← Sebelumnya: Node.js Application Berikutnya: Python WSGI/ASGI →