PHP-FPM Kurulumu ve Nginx Entegrasyonu

Nginx tek başına PHP dosyalarını çalıştıramaz. Bu yüzden PHP-FPM (FastCGI Process Manager) devreye giriyor. Klasik Apache + mod_php ikilisinin aksine, Nginx ile PHP-FPM arasında FastCGI protokolü üzerinden iletişim kurulur ve bu yaklaşım hem kaynak kullanımı hem de performans açısından ciddi avantajlar sağlar. Bu yazıda sıfırdan kurulumdan, çoklu PHP sürüm yönetimine kadar tüm süreci ele alacağız.

PHP-FPM Nedir, Neden Kullanılır?

PHP-FPM, PHP’nin kendi içinde gelen bir FastCGI implementasyonudur. Normal PHP-CGI’nin aksine worker process havuzu yönetir, yani her istek için yeni bir process başlatmak yerine mevcut process’leri yeniden kullanır. Bu da sunucunun hem daha hızlı hem de daha az kaynak tüketerek çalışmasını sağlar.

Nginx’in PHP-FPM ile çalışma mantığı şöyledir: Nginx, gelen isteği alır, PHP dosyası olduğunu anlar ve isteği Unix socket ya da TCP socket üzerinden PHP-FPM’e iletir. PHP-FPM bu isteği işler ve sonucu Nginx’e geri döner. Nginx de bunu istemciye gönderir. Bu mimaride Nginx statik dosyaları kendisi servis ederken PHP işlemlerini tamamen PHP-FPM’e devreder.

Özellikle yüksek trafikli sitelerde bu ayrım kritiktir. Nginx’in event-driven mimarisi statik içeriği çok verimli sunarken, PHP-FPM pool yapılandırmasıyla PHP işlemcilerini bağımsız olarak ölçeklendirebilirsiniz.

Kurulum

Ubuntu/Debian Sistemlerde

# Sistemin paket listesini güncelle
sudo apt update

# Nginx kur
sudo apt install nginx -y

# PHP-FPM kur (örneğin PHP 8.2)
sudo apt install php8.2-fpm php8.2-cli php8.2-common -y

# Sık kullanılan eklentileri de kuralım
sudo apt install php8.2-mysql php8.2-curl php8.2-gd php8.2-mbstring php8.2-xml php8.2-zip php8.2-intl -y

CentOS/RHEL/AlmaLinux Sistemlerde

# EPEL ve Remi repo'larını ekle
sudo dnf install epel-release -y
sudo dnf install https://rpms.remirepo.net/enterprise/remi-release-9.rpm -y

# PHP 8.2'yi etkinleştir
sudo dnf module reset php -y
sudo dnf module enable php:remi-8.2 -y

# Kurulumu gerçekleştir
sudo dnf install php php-fpm php-cli php-common php-mysqlnd php-curl php-gd php-mbstring php-xml php-zip -y

# Nginx'i kur
sudo dnf install nginx -y

Kurulumdan sonra servislerin durumunu kontrol edelim:

# Servisleri başlat ve boot'ta otomatik başlamasını sağla
sudo systemctl start php8.2-fpm
sudo systemctl enable php8.2-fpm
sudo systemctl start nginx
sudo systemctl enable nginx

# Durum kontrolü
sudo systemctl status php8.2-fpm
sudo systemctl status nginx

PHP-FPM Pool Yapılandırması

PHP-FPM’in en güçlü özelliklerinden biri pool sistemidir. Her proje ya da site için ayrı bir pool oluşturabilirsiniz. Bu hem güvenlik hem de kaynak yönetimi açısından büyük avantaj sağlar.

Pool konfigürasyon dosyaları genellikle /etc/php/8.2/fpm/pool.d/ dizininde bulunur. Varsayılan www.conf dosyasını inceleyelim ve özelleştirelim:

sudo nano /etc/php/8.2/fpm/pool.d/www.conf

Kritik parametreleri açıklayalım:

  • [www]: Pool adı, log dosyalarında ve process listesinde bu isim görünür
  • user ve group: PHP-FPM worker’larının hangi kullanıcı altında çalışacağı
  • listen: Socket tipi ve adresi, Unix socket için /run/php/php8.2-fpm.sock
  • pm: Process manager tipi, static, dynamic veya ondemand olabilir
  • pm.max_children: Aynı anda çalışabilecek maksimum child process sayısı
  • pm.start_servers: Başlangıçta açılacak process sayısı
  • pm.min_spare_servers: Minimum boşta bekleyen process sayısı
  • pm.max_spare_servers: Maksimum boşta bekleyen process sayısı
  • pm.max_requests: Bir process’in kaç istek işledikten sonra yeniden başlayacağı

Gerçek bir WordPress sitesi için örnek pool konfigürasyonu:

[wordpress_site]
user = www-data
group = www-data
listen = /run/php/php8.2-wordpress.sock
listen.owner = www-data
listen.group = www-data
listen.mode = 0660

pm = dynamic
pm.max_children = 20
pm.start_servers = 4
pm.min_spare_servers = 2
pm.max_spare_servers = 6
pm.max_requests = 500

; Yavaş sorguları logla (3 saniyeden uzun süren işlemler)
slowlog = /var/log/php-fpm/wordpress-slow.log
request_slowlog_timeout = 3s

; Çevre değişkenleri
env[HOSTNAME] = $HOSTNAME
env[PATH] = /usr/local/bin:/usr/bin:/bin
env[TMP] = /tmp
env[TMPDIR] = /tmp
env[TEMP] = /tmp

; PHP ayarları override
php_admin_value[error_log] = /var/log/php-fpm/wordpress-error.log
php_admin_flag[log_errors] = on
php_value[session.save_handler] = files
php_value[session.save_path] = /var/lib/php/sessions
php_value[upload_max_filesize] = 64M
php_value[post_max_size] = 64M
php_value[memory_limit] = 256M

Nginx Konfigürasyonu

Şimdi Nginx tarafını yapılandıralım. /etc/nginx/sites-available/ dizininde yeni bir site konfigürasyonu oluşturuyoruz:

sudo nano /etc/nginx/sites-available/wordpress.example.com
server {
    listen 80;
    server_name wordpress.example.com www.wordpress.example.com;
    root /var/www/wordpress;
    index index.php index.html index.htm;

    # Access ve error logları
    access_log /var/log/nginx/wordpress.access.log;
    error_log /var/log/nginx/wordpress.error.log;

    # Gzip sıkıştırma
    gzip on;
    gzip_types text/plain text/css application/json application/javascript text/xml application/xml application/xml+rss text/javascript;

    # Statik dosyalar için cache
    location ~* .(jpg|jpeg|png|gif|ico|css|js|woff|woff2|ttf|svg)$ {
        expires 30d;
        add_header Cache-Control "public, no-transform";
    }

    # WordPress için ana location bloğu
    location / {
        try_files $uri $uri/ /index.php?$args;
    }

    # PHP dosyalarını PHP-FPM'e ilet
    location ~ .php$ {
        # Güvenlik: Mevcut olmayan dosyaları PHP'ye gönderme
        try_files $uri =404;

        # fastcgi_split_path_info ile PATH_INFO ayrıştır
        fastcgi_split_path_info ^(.+.php)(/.+)$;

        # PHP-FPM socket'e bağlan
        fastcgi_pass unix:/run/php/php8.2-wordpress.sock;
        fastcgi_index index.php;

        # FastCGI parametrelerini dahil et
        include fastcgi_params;
        fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
        fastcgi_param PATH_INFO $fastcgi_path_info;

        # Timeout değerleri
        fastcgi_read_timeout 300;
        fastcgi_connect_timeout 60;
        fastcgi_send_timeout 300;

        # Buffer ayarları
        fastcgi_buffer_size 128k;
        fastcgi_buffers 4 256k;
        fastcgi_busy_buffers_size 256k;
    }

    # .htaccess ve gizli dosyalara erişimi engelle
    location ~ /. {
        deny all;
    }

    # xmlrpc.php'yi engelle (WordPress brute force koruması)
    location = /xmlrpc.php {
        deny all;
    }
}

Konfigürasyonu etkinleştirelim ve test edelim:

# Symlink oluştur
sudo ln -s /etc/nginx/sites-available/wordpress.example.com /etc/nginx/sites-enabled/

# Konfigürasyon sözdizimini kontrol et
sudo nginx -t

# Nginx'i yeniden yükle
sudo systemctl reload nginx

Çoklu PHP Sürümü Yönetimi

Bu konu özellikle ajans ortamlarında veya farklı PHP gereksinimlerine sahip birden fazla proje barındıran sunucularda kritik önem taşır. Diyelim ki bir siteniz PHP 7.4 gerektiriyor, diğeri PHP 8.2 kullanıyor.

# Önce ondrej/php PPA'sını ekleyelim (Ubuntu için)
sudo add-apt-repository ppa:ondrej/php -y
sudo apt update

# Birden fazla PHP sürümünü kur
sudo apt install php7.4-fpm php7.4-mysql php7.4-curl php7.4-gd php7.4-mbstring -y
sudo apt install php8.1-fpm php8.1-mysql php8.1-curl php8.1-gd php8.1-mbstring -y
sudo apt install php8.2-fpm php8.2-mysql php8.2-curl php8.2-gd php8.2-mbstring -y

# Her birini başlat
sudo systemctl start php7.4-fpm php8.1-fpm php8.2-fpm
sudo systemctl enable php7.4-fpm php8.1-fpm php8.2-fpm

Artık her sitenin Nginx konfigürasyonunda farklı bir socket kullanabilirsiniz:

# Eski proje - PHP 7.4
server {
    server_name eski-proje.example.com;
    # ...
    location ~ .php$ {
        fastcgi_pass unix:/run/php/php7.4-fpm.sock;
        # ...
    }
}

# Yeni proje - PHP 8.2
server {
    server_name yeni-proje.example.com;
    # ...
    location ~ .php$ {
        fastcgi_pass unix:/run/php/php8.2-fpm.sock;
        # ...
    }
}

Performans Optimizasyonu

OPcache Yapılandırması

OPcache, PHP betiklerinin derlenmis bytecode halini bellekte saklar ve her istekte yeniden derleme yapmaktan kurtarır. Performans artışı %50 ile %80 arasında olabilir.

sudo nano /etc/php/8.2/fpm/conf.d/10-opcache.ini
opcache.enable=1
opcache.enable_cli=0
opcache.memory_consumption=256
opcache.interned_strings_buffer=16
opcache.max_accelerated_files=10000
opcache.max_wasted_percentage=10
opcache.validate_timestamps=0
opcache.revalidate_freq=0
opcache.fast_shutdown=1
opcache.jit_buffer_size=100M
opcache.jit=1255

Not: validate_timestamps=0 production’da kullanılır. Geliştirme ortamında 1 yaparak her dosya değişikliğinin otomatik algılanmasını sağlayabilirsiniz.

PHP-FPM Process Manager Seçimi

Sunucu kaynaklarınıza göre doğru pm tipini seçmek önemlidir:

  • static: pm.max_children kadar process her zaman çalışır. Kararlı yüksek trafikte idealdir, bellek kullanımı sabittir.
  • dynamic: Process sayısı talebe göre pm.min_spare_servers ile pm.max_children arasında değişir. Çoğu senaryo için en dengeli seçenektir.
  • ondemand: Sadece istek geldiğinde process açılır. Düşük trafikli sitelerde bellek tasarrufu sağlar ancak ilk istek biraz yavaş olabilir.

Kaç tane max_children ayarlamanız gerektiğini hesaplamak için şu yaklaşımı kullanabilirsiniz:

# Mevcut PHP-FPM process'lerinin bellek kullanımına bak
ps aux | grep php-fpm | awk '{sum += $6} END {print "Toplam: " sum/1024 " MB"}'

# Her process ortalama kaç MB kullanıyor?
# Örnek: 10 process 512MB kullanıyorsa, her biri ~51MB
# Sunucuda PHP'ye 2GB ayırdıysanız: 2048MB / 51MB ≈ 40 max_children

Güvenlik Yapılandırması

sudo nano /etc/php/8.2/fpm/php.ini
; Tehlikeli fonksiyonları devre dışı bırak
disable_functions = exec,passthru,shell_exec,system,proc_open,popen,curl_exec,curl_multi_exec,parse_ini_file,show_source

; PHP sürümünü gizle
expose_php = Off

; Hata mesajlarını kullanıcıya gösterme
display_errors = Off
log_errors = On
error_log = /var/log/php/error.log

; Session güvenliği
session.cookie_httponly = 1
session.cookie_secure = 1
session.use_strict_mode = 1

; Dosya yükleme limitleri
upload_max_filesize = 32M
post_max_size = 32M
max_execution_time = 60
max_input_time = 60
memory_limit = 256M

Sorun Giderme

Gerçek hayatta en çok karşılaşılan sorunlar ve çözümleri:

502 Bad Gateway hatası: PHP-FPM çalışmıyor ya da socket yolu yanlış.

# PHP-FPM durumunu kontrol et
sudo systemctl status php8.2-fpm

# Socket dosyasının varlığını kontrol et
ls -la /run/php/php8.2-fpm.sock

# Nginx hata loguna bak
sudo tail -f /var/log/nginx/error.log

# PHP-FPM loguna bak
sudo tail -f /var/log/php8.2-fpm.log

PHP-FPM status sayfası: Pool’ların durumunu izlemek için çok kullanışlıdır:

# Nginx konfigürasyonuna status endpoint ekle
location ~ ^/(status|ping)$ {
    include fastcgi_params;
    fastcgi_pass unix:/run/php/php8.2-fpm.sock;
    fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
    allow 127.0.0.1;
    deny all;
}
# Status sayfasını sorgula
curl http://localhost/status?full

Pool konfigürasyon dosyasına da eklemek gerekir:

pm.status_path = /status
ping.path = /ping

Gerçek Dünya Senaryosu: Laravel Projesi

Laravel uygulamaları için özel Nginx konfigürasyonu biraz farklıdır çünkü public/ dizini document root’tur:

server {
    listen 80;
    server_name api.example.com;
    root /var/www/laravel-app/public;
    index index.php;

    access_log /var/log/nginx/laravel.access.log;
    error_log /var/log/nginx/laravel.error.log;

    # Laravel'in tüm istekleri index.php'ye yönlendirmesi için
    location / {
        try_files $uri $uri/ /index.php?$query_string;
    }

    # Statik asset'ler
    location ~* .(js|css|png|jpg|jpeg|gif|ico|svg|woff|woff2)$ {
        expires max;
        log_not_found off;
    }

    location ~ .php$ {
        try_files $uri =404;
        fastcgi_split_path_info ^(.+.php)(/.+)$;
        fastcgi_pass unix:/run/php/php8.2-laravel.sock;
        fastcgi_index index.php;
        include fastcgi_params;
        fastcgi_param SCRIPT_FILENAME $realpath_root$fastcgi_script_name;
        fastcgi_param DOCUMENT_ROOT $realpath_root;
        fastcgi_read_timeout 300;
    }

    # Storage ve bootstrap cache'e dışarıdan erişimi engelle
    location ~ ^/(storage|bootstrap/cache) {
        deny all;
    }
}

Sonuç

PHP-FPM ve Nginx entegrasyonu, başta karmaşık görünse de bir kez kurulduktan sonra son derece esnek ve güçlü bir platform sunuyor. Pool sistemi sayesinde aynı sunucuda farklı PHP sürümleri çalıştırabilir, her uygulama için izole bir çalışma ortamı oluşturabilirsiniz. OPcache ile birleştiğinde bu kombinasyon, Apache + mod_php’ye kıyasla ciddi performans avantajı sağlar.

Özellikle dikkat etmeniz gereken noktalar şunlardır: pool boyutunu sunucu RAM’inize göre hesaplayın, production’da OPcache validate_timestamps değerini kapatın, her uygulama için ayrı pool ve socket kullanın, güvenlik ayarlarını ihmal etmeyin. Slow log ve status sayfası özelliklerini aktif tutarsanız olası performans sorunlarını erken tespit edebilirsiniz. Bu altyapıyı bir kez doğru kurduğunuzda üzerine ölçeklendirmek oldukça kolaylaşıyor.

Bir yanıt yazın

E-posta adresiniz yayınlanmayacak. Gerekli alanlar * ile işaretlenmişlerdir