Instalacja i konfiguracja FastCGI / PHP5-FPM

Standardowo serwer Apache obsługuje PHP5 jako moduł php5_mod, który co prawda jest dość szybki jednak ma pewne ograniczenia związane z konfiguracją jak i z ograniczeniem bezpieczeństwa. Problem ten można rozwiązać wykorzystując moduł FCGI ( Fast CGI ) wraz z PHP-FPM. Rozwiązanie takie daje nam znacznie większe możliwości konfiguracji interpretera PHP jak i zwiększa poziom bezpieczeństwa. Najogólniej można by wymienić chociażby możliwość niezależnej konfiguracji dyrektyw z php.ini dla każdego użytkownika / vhosta czy też uruchamianie skryptów z prawami użytkownika.

Instalacja FastCGI i PHP5-FPM

Instalacja i konfiguracja była przeprowadzana na systemach Ubuntu Mate 4.2 na X86 jak na na ARM ( Raspberry Pi 2 ), Debian Wheezy.
Na samym początku aktualizujemy repozytoria i pakiety:

sudo apt-get update
sudo apt-get upgrade

Instalujemy moduł FastCGI dla serwera Apache i pakiet odpowiedzialny za obsługę menadżera procesów dla PHP5 ( PHP5-FPM – skrót FPM: FastCgi Process Manager ), który będzie uruchamiany za pośrednictwem modułu FastCGI:

sudo apt-get install libapache2-mod-fastcgi
sudo apt-get install php5-fpm

Sprawdzamy listę zainstalowanych modułów serwera Apache:

sudo apache2ctl -M | sort

Lista powinna zawierać moduł fastcgi_module Najprawdopodobniej będzie tam też aktywny standardowy moduł php5, tak więc wyłączamy go wydając poniższe polecenie:

sudo a2dismod php5

Włączamy dodatkowo poniższy moduł:

sudo a2enmod actions

Konfiguracja

Sprawdzamy w domyślnym pliku konfiguracyjnym php5-fpm wartość opcji listen w pliku: /etc/php5/fpm/pool.d/www.conf lub aby od razu wyświetlił nam w konsoli wartość tej opcji wypisujemy poniższe polecenie:

sudo grep -E '^\s*listen\s*=\s*[a-zA-Z/]+’ /etc/php5/fpm/pool.d/www.conf

Jeśli w pliku konfiguracyjnym modułu /etc/php5/fpm/pool.d/www.conf został znaleziony wpis jak poniżej:

listen = 127.0.0.1:9000

zastępujemy go na na:

listen = /var/run/php5-fpm.sock

Teraz moduł będzie komunikował się poprzez sockety, dzięki czemu każdy virtualhost będzie miał swój własny socket utworzony w odrębnych plikach konfiguracyjnych utworzonych na podstawie domyślnego pliku www.conf.
Plik www.conf jest plikiem domyślnym, tak więc jeśli dyrektywy z tego pliku nie są nadpisane na przykład w konfiguracjach poszczególnych virtualhostów to ustawienia będą odnosić się do wszystkich udostępnionych zasobów. Tak więc jeśli chcemy wprowadzić jakieś restrykcje dotyczące PHP to zalecam utworzenie dla wybranych przez nas virtualhostów odrębnych plików utworzonych na podstawie pliku www.conf Tam też możemy ustawiać indywidualne ustawienia interpretera PHP i innych zabezpieczeń ( bez tworzenia odrębnych plików php.ini ). Jeśli jakiś virtualhost nie będzie miał takowego pliku konfiguracyjnego to domyślnie będzie korzystał właśnie z ustawień pliku: www.conf. Konfiguracja php5-fpm w kontekście wirtualnych hostów została opisana w dalszej części opracowania.

Sprawdzamy wersję serwera Apache:

apache2 -v lub apache2ctl -v

Konfigurujemy moduł: /etc/apache2/mods-enabled/fastcgi.conf

Dla Apache 2.2 lub wcześniejszych:


Dla Apache 2.4 i późniejszych:


Sprawdzamy poprawność konfiguracji:

sudo apache2ctl configtest

Restart php5-fpm i Apache:

sudo service apache2 restart
sudo service php5-fpm restart

Teraz serwer Apache powinien automatycznie uruchamiać php5-fpm poprzez moduł FastCGI w momencie napotkania kodu PHP.
Aby pobrać więcej informacji na temat bierzącej konfiguracji skorzystamy z funkcji phpinfo().
Tworzymy przykładowy plik na przykład: test.php w lokalizacji w której trzymamy dokumenty html, domyślnie jest to: /var/www/html

wpisując do niego:

phpinfo();

Teraz możemy sprawdzić na jakim module PHP działa nasz Apache, jeśli wszystko zrobiliśmy zgodnie z opisem powinno być:

Server API : FPM/FastCGI

zamiast domyślnej obsługi modułu php5:

Server API : Apache 2.0 Handler

Konfiguracja VirtualHostów

Tutaj będziemy mogli już wykorzystywać pliki konfiguracyjne php.ini osobno dla poszczególnych virtualhostów a w zasadzie korzystać z pliku konfiguracyjnego tworzonego na podstawie domyślnego pliku www.conf w którym, będziemy mogli zastosować opcje i flagi z php.ini. Tak jak wcześniej wspomniałem jeśli jakiś wirtualny host nie będzie miał odrębnej konfiguracji to będzie korzystał z domyślnej konfiguracji zawartej w pliku: www.conf.

Konfigurujemy poszczególne pliki konfiguracyjne php5-fpm powiązane z naszymi virtualhostami, bazując na pliku domyślnym www.conf, dla przykładu:

cp /etc/php5/fpm/pool.d/www.conf /etc/php5/fpm/pool.d/nasza-domena.com.conf

W tychże plikach konfiguracyjnych możemy dodawać opcje z php.ini dla poszczególnych vhostów. Tak więc każdy virtualhost będzie mógł mieć swoje własne ustawienia zgodne z dyrektywami php.ini.

Podstawowa konfiguracja dotyczy zmiany nazwy virtualhosta, użytkownika i grupy z jakim ma być uruchamiany proces jak i z lokalizacją indywidualnego pliku z socketem. Do tego mamy wiele innych opcji, które możemy indywidualnie dopasować do konfiguracji naszych wirtualnych hostów. Pamiętajmy o zastąpieniu ciągu: nasz-vhost.com właściwą nazwą dla naszego vhosta !

Przykładowy plik konfiguracyjny /etc/php5/fpm/pool.d/nasz-vhost.com:

; Start a new pool named 'www'.
; the variable $pool can we used in any directive and will be replaced by the
; pool name ('www' here)
[nasz-vhost.com]
...
; Unix user/group of processes
; Note: The user is mandatory. If the group is not set, the default user's group
;       will be used.
user = mac
group = mac
...
listen = /var/run/php5-fpm_nasz-vhost.com.sock

Restartujemy php5-fpm:

sudo service php5-fpm restart

Teraz pozostaje już standardowa konfiguracja/tworzenie wirtualnych hostów dla serwera Apache. Tworzymy plik z naszym nowym wirtualnym hostem na przykład na podstawie domyślnego pliku:

sudo cp /etc/apache2/sites-available/000-default.conf /etc/apache2/sites-available/001-nasz-vhost.com

Aktywujemy virtualhosta tworząc odpowiedni link symboliczny:

ln -s /etc/apache2/sites-available/001-nasz-vhost.com /etc/apache2/sites-enabled/001-nasz-vhost.com

Przykładowy minimalistyczny plik konfiguracyjny virtualhosta z wykorzystaniem obsługi mod_fastcgi:


Sprawdzamy poprawność konfiguracji Apacha:

sudo apache2ctl configtest

Restart php5-fpm i Apache:

sudo service apache2 restart
sudo service php5-fpm restart

Przykład

Ostatnio musiałem wprowadzić restrykcję dla większości virtualhostów poza kilkoma, które miały być „zaufane” i miały mieć pełny zestaw funkcji. Plik php.ini dla php-5fpm znajduje się w lokalizacji: /etc/php5/fpm/php.ini
Problem polegał na tym, iż w php.ini nie można nadpisać dyrektywy: disable_functions dla poszczególnych virtualhostów ( przysłonięcie dyrektywy z wykorzystanie php_admin_value w konfiguracji vhosta ). Tak więc w takich sytuacjach należy wykorzystywać indywidualne pliki konfiguracyjne www.conf i ich pochodne dla poszczególnych vhostów w celu niezależnej konfiguracji dyrektyw PHP.

Tak więc dla przykładu, jeśli do naszego głównego pliku konfiguracyjnego: www.conf wprowadzimy opcję:

php_admin_value[disable_functions] = pcntl_alarm,pcntl_fork,pcntl_waitpid,pcntl_wait,pcntl_w     ifexited,pcntl_wifstopped,pcntl_wifsignaled,pcntl_wexitstatus,pcntl_wtermsi     g,pcntl_wstopsig,pcntl_signal,pcntl_signal_dispatch,pcntl_get_last_error,pc     ntl_strerror,pcntl_sigprocmask,pcntl_sigwaitinfo,pcntl_sigtimedwait,pcntl_e     xec,pcntl_getpriority,pcntl_setpriority,system,exec,passthru,shell_exec,fso     ckopen,proc_open,popen,set_time_limit,php_uname,phpinfo

to wszystkie nasze udostępnione zasoby będą miały zablokowane wyżej wymienione funkcje podczas uruchamiania interpretera PHP oczywiście poza tymi vhostami, które posiadają własne pliki konfiguracyjne – NIEZALEŻNE od domyślnego pliku www.conf. Na przykład jeśli mamy w pliku konfiguracyjnym naszego zaufanego vhosta /etc/php5/fpm/pool.d/nasz-vhost.com dodaną opcję:

php_admin_value[disable_functions] =

to wtedy nie mamy, żadnych zablokowanych funkcji – jeszcze raz podkreślam dyrektywa w tych plikach przysłania dyrektywę z pliku php.ini dla php5-fpm !

Problemy

+ Internal Server Error 500

Powodów tego błędu może być wiele… jednym z nich jest zbyt długi czas wykonywania skryptu i ograniczeniami ze strony konfiguracji PHP / FastCGI.
Nawet jeśli ustawimy prawidłowo dyrektywę max_execution_time na odpowiednio dużą wartość w php.ini lub plikach konfiguracyjnych w php5-fpm przysłaniających ową dyrektywę z php.ini to nie rozwiąże to naszego problemu. Musimy wziąć pod uwagę iż FastCGI domyślnie pozwala na wywołanie procesu PHP na nie dłużej niż na 30 sekund. Tak więc musimy brać pod uwagę obie opcje dotyczące tego ograniczenia.
Jeśli już ustawiliśmy odpowiednią wartość dla limitu czasowego określającego maksymalny czas wykonywania skryptu PHP max_execution_time musimy jeszcze wprowadzić odpowiednią opcję w module FastCGI.

Konfigurację przeprowadzamy dla modułu FastCGI ( domyślna konfiguracja ) w lokalizacji: /etc/apache2/mods-enabled/fastcgi.conf lub dla poszczególnych virtualhostów: /etc/apache2/sites-enabled/nasz-vhost.conf ( z przysłonięciem wartości domyślnej )

Pogrubioną czcionką zaznaczyłem naszą opcję odpowiedzialną za maksymalny czas trwania procesu PHP i jak widać jest to konfiguracja domyślna ( brak identyfikatorów vhostów po php5-fcgi )

FastCgiExternalServer /usr/lib/cgi-bin/php5-fcgi -socket /var/run/php5-fpm.sock -pass-header Authorization -idle-timeout 900

Tutaj to samo dla vhostów z dodanymi identyfikatorami vhostów ( /etc/apache2/sites-enabled/ ):

 FastCgiExternalServer /usr/lib/cgi-bin/php5-fcgi_nasz-vhost.com -socket /var/run/php5-fpm_nasz-vhost.com.sock -pass-header Authorization -idle-timeout 900

Słowa kluczowe: fastcgi, php5-fpm, php.ini dla virtualhosta, vhost, bezpieczeństwo php, disable_functions, problem, timeout, internal server error 500

Dodaj komentarz