PHP-FPM

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 =404 di 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-Cache header untuk memantau hit rate.
  • Tuning pm.max_children di PHP-FPM berdasarkan RAM yang tersedia dibagi memory per proses — terlalu tinggi bisa menyebabkan server swap.

← Sebelumnya: Node.js App   Berikutnya: Python WSGI →

About | Author | Content Scope | Editorial Policy | Privacy Policy | Disclaimer | Contact