Ana içeriğe geç

PHP-FPM kurulumu#

Bu sayfa uzun yıllar "CentOS 7'de PHP 7 ve PHP-FPM kurulumu" başlığıyla yaşadı. CentOS 7'nin desteği Haziran 2024'te bitti, PHP 7'nin desteği ondan da önce, 2019'da bitmişti. Link hâlâ elimizde duruyor ama içeriği artık doğru olmayan bir şeyi öğretmemeli - o yüzden aynı soruyu güncel dağıtım ve sürümlerle yeniden yazdık. Mantık aynı, komutlar farklı.

PHP-FPM nedir, neden mod_php değil#

PHP-FPM (FastCGI Process Manager), PHP'yi web sunucusunun kendi sürecinden ayrı, bağımsız worker havuzları halinde çalıştırır. nginx zaten PHP çalıştıramaz - Apache'nin aksine bir PHP modülü yoktur - o yüzden nginx kullanan her kurulumda PHP-FPM zorunludur. Apache tarafında bile bugün mod_php yerine PHP-FPM tercih edilir: süreç izolasyonu, bağımsız yeniden başlatma ve daha öngörülebilir bellek kullanımı sağlar.

Hangi PHP sürümünü kurmalıyım#

PHP her Kasım'da yeni bir minör sürüm çıkarır; her sürüm ~2 yıl aktif, +1 yıl da yalnızca güvenlik yaması alır. "En güncel sürüm" bu sayfa yazıldıktan sonra da değişmeye devam edecek, o yüzden burada sabit bir numaraya değil php.net/supported-versions sayfasına bakın - o an aktif desteği olan sürümleri gerçek zamanlı gösterir.

Pratik kural

Yeni bir proje kuruyorsanız listedeki en güncel sürümü seçin. Var olan bir uygulamayı taşıyorsanız ve o uygulama eski bir sürüme kilitliyse, aşağıdaki "Birden fazla PHP sürümü aynı sunucuda" bölümüne bakın - illa en eskisini sistem geneline yaymanıza gerek yok.

Aşağıdaki örneklerde 8.4 kullanıyoruz; kendi tercih ettiğiniz sürüme göre değiştirin, adımların mantığı hepsinde aynı.

1. Paketleri kurun#

Dağıtımın kendi depoları genelde bir-iki sürüm geriden gelir. Güncel sürümlere erişmek için Ondřej Surý'nin PPA'sı - CentOS 7 döneminden beri PHP dünyasının fiili standardı - hâlâ referans kaynaktır:

sudo apt update
sudo apt install -y software-properties-common
sudo add-apt-repository -y ppa:ondrej/php
sudo apt update
sudo apt install -y nginx php8.4-fpm php8.4-cli php8.4-mysql \
  php8.4-curl php8.4-gd php8.4-mbstring php8.4-xml php8.4-zip

Dağıtımın kendi deposuyla yetiniyorsanız paket adlarından sürüm numarasını çıkarın (php-fpm, php-cli, …) - o zaman Ubuntu/Debian sürümünün varsayılanını alırsınız.

sudo dnf install -y https://dl.fedoraproject.org/pub/epel/epel-release-latest-9.noarch.rpm
sudo dnf install -y https://rpms.remirepo.net/enterprise/remi-release-9.rpm
sudo dnf module reset php
sudo dnf module enable -y php:remi-8.4
sudo dnf install -y nginx php-fpm php-cli php-mysqlnd php-curl php-gd php-mbstring php-xml php-zip

CentOS 7'nin doğrudan devamı olmasa da, Rocky/AlmaLinux bugün RHEL ailesinde aynı rolü oynuyor - Remi deposu da CentOS 7 döneminden beri aynı işi yapıyor. remi-8.4 yerine güncel sürüm ne ise onu yazın (dnf module list php mevcut seçenekleri gösterir).

Bu komutlar EL9 içindir

epel-release-latest-9 ve remi-release-9 paket adlarındaki 9, major EL sürümüne (Rocky/AlmaLinux 9) özeldir - EL8'de epel-release-latest-8 + remi-release-8, EL10'da epel-release-latest-10 + remi-release-10 gerekir. Yanlış sürüm numarasıyla kurulum bağımlılık çakışmasıyla başarısız olur. Kendi major sürümünüzü cat /etc/os-release ile doğrulayın.

Morpheus ile

"sunucuma en güncel php-fpm sürümünü kur, nginx zaten kurulu"

Morpheus dağıtımı tanır, hangi sürümlerin depoda mevcut olduğuna bakar ve doğru depo/paket adını seçer; RHEL ailesinde modül etkinleştirme adımını da o çalıştırır.

2. Havuzu (pool) yapılandırın#

PHP-FPM, her site/uygulama için ayrı bir "havuz" tanımlar. Havuz dosyasının konumu ve içindeki soket yolu dağıtıma göre değişir - ikisini karıştırırsanız 502 alırsınız, o yüzden ayrı ayrı veriyoruz.

/etc/php/8.4/fpm/pool.d/www.conf
[www]
user = www-data
group = www-data
listen = /run/php/php8.4-fpm.sock
listen.owner = www-data
listen.group = www-data
pm = dynamic
pm.max_children = 10
pm.start_servers = 2
pm.min_spare_servers = 1
pm.max_spare_servers = 4
sudo systemctl restart php8.4-fpm
/etc/php-fpm.d/www.conf
[www]
user = nginx
group = nginx
listen = /run/php-fpm/www.sock
listen.owner = nginx
listen.group = nginx
pm = dynamic
pm.max_children = 10
pm.start_servers = 2
pm.min_spare_servers = 1
pm.max_spare_servers = 4
sudo systemctl restart php-fpm

user/group yerine yalnızca soket iznini paylaşmak isterseniz

Yukarıdaki user/group değerlerini nginx'inkiyle aynı yapmak en basit yol - tek siteli bir sunucuda pratikte sorun çıkarmaz. Ama FPM worker'larının kendi kimliğini korumasını (nginx'ten ayrı bir kullanıcı) istiyorsanız, user/group'u değiştirmek yerine yalnızca listen.owner/listen.group/listen.mode satırlarını nginx'in çalıştığı kullanıcıya göre ayarlamanız yeterli - soket izni ile worker kimliği ayrı şeylerdir, ikincisini değiştirmeden birincisini çözebilirsiniz.

3. nginx'e bağlayın#

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

    location / {
        try_files $uri $uri/ /index.php?$args;
    }

    location ~ \.php$ {
        include snippets/fastcgi-php.conf;
        fastcgi_pass unix:/run/php/php8.4-fpm.sock;
    }

    location ~ /\.(?!well-known) {
        deny all;
    }
}

Debian/Ubuntu'nun nginx paketi yalnızca sites-enabled/ altındakini yükler - sites-available/'a yazmak tek başına yeterli değil, sembolik bağla etkinleştirmeniz gerekir:

sudo ln -s /etc/nginx/sites-available/example.com /etc/nginx/sites-enabled/example.com
sudo nginx -t && sudo systemctl reload nginx

RHEL ailesinin nginx paketi sites-available/sites-enabled kullanmaz - her şey conf.d/ altına düz .conf dosyası olarak yazılır, ayrıca etkinleştirme adımı gerekmez. snippets/fastcgi-php.conf de Debian paketine özeldir; RHEL'de fastcgi parametrelerini elle eklersiniz:

/etc/nginx/conf.d/example.com.conf
server {
    listen 80;
    server_name example.com;
    root /var/www/example.com;
    index index.php index.html;

    location / {
        try_files $uri $uri/ /index.php?$args;
    }

    location ~ \.php$ {
        include fastcgi_params;
        fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
        fastcgi_pass unix:/run/php-fpm/www.sock;
    }

    location ~ /\.(?!well-known) {
        deny all;
    }
}
sudo nginx -t && sudo systemctl reload nginx

fastcgi_pass yolu, 2. adımda listen için yazdığınız soketle birebir aynı olmalı. Bu ikisi arasındaki en ufak yazım farkı 502 Bad Gateway ile sonuçlanır - listedeki en sık PHP-FPM hatası budur.

4. Test edin (ve hemen silin)#

echo "<?php phpinfo();" | sudo tee /var/www/example.com/info.php

https://example.com/info.php sayfasını açın, PHP sürümünü ve yüklü modülleri görün.

info.php'yi kalıcı bırakmayın

phpinfo() sunucu yollarını, yüklü modülleri ve bazen ortam değişkenlerini dışarı sızdırır. Test biter bitmez silin:

sudo rm /var/www/example.com/info.php

Birden fazla PHP sürümü aynı sunucuda#

Eski bir uygulama daha eski bir sürüme kilitliyken yeni bir tanesi güncelini istiyorsa (mesela 8.1 ile 8.4 bir arada), ikisini yan yana kurabilirsiniz - her sürümün kendi FPM havuzu, kendi soketi olur (php8.1-fpm.sock, php8.4-fpm.sock), site bazında nginx fastcgi_pass ile hangisine gideceğini seçer. Sistem genelindeki php komutu tek sürüme bağlıdır; update-alternatives --config php (Debian) ile CLI tarafını değiştirebilirsiniz. Eski sürümü yalnızca o uygulama için tutun - güvenlik desteği bittiyse yeni site açarken bir daha seçmeyin.

Sorun giderme#

502 Bad Gateway - neredeyse her zaman soket/port uyuşmazlığı. nginx'teki fastcgi_pass ile FPM havuzundaki listen aynı değeri taşımıyor, ya da FPM servisi hiç ayakta değil (systemctl status php8.4-fpm Debian/Ubuntu'da, systemctl status php-fpm RHEL ailesinde).

"Permission denied" FPM loglarında - user/group sunucudaki gerçek kullanıcıyla uyuşmuyor, ya da dosya izinleri çok kısıtlayıcı. Önce hangi dosya/dizinde takıldığını log'dan görün, yalnızca o yolun sahipliğini düzeltin (chown www-data:www-data /var/www/example.com/o-dosya) - tüm site köküne kör kör chown -R uygulamak, uygulama koduyla yüklenen içeriği aynı sahiplikte bırakır ve web süreci ele geçirilirse kod dosyalarını da yazılabilir hale getirir.

Değişiklik etki etmiyor - FPM'i reload değil restart etmeniz gerekebilir; havuz dosyası değişiklikleri yalnızca yeniden başlatmada okunur.

Morpheus ile

"php-fpm neden 502 veriyor bak"

Morpheus nginx error log'unu, FPM servis durumunu ve soket dosyasının varlığını kontrol eder, hangisinin eksik olduğunu söyler.

Kontrol listesi#

  • [ ] systemctl status php8.4-fpm (Debian/Ubuntu) ya da systemctl status php-fpm (RHEL ailesi) active (running)
  • [ ] nginx -tsyntax is ok
  • [ ] fastcgi_pass ve FPM listen aynı soketi gösteriyor
  • [ ] info.php test edildi ve silindi
  • [ ] user/group değerleri nginx'in çalıştığı kullanıcıyla eşleşiyor