eRIZ's weblog

PHP, webdesign, Linux, Windows i inne, bo nie samym chlebem człowiek żyje

Niezawodny serwer – FreeBSD + Nginx + PHP @ FastCGI

Ostatnio o Nginksie pisałem już jakiś czas temu. Pozmieniało się sporo, sam rozwój tego demona był dla mnie sporym zaskoczeniem. Kiedyś niszowy projekt – dzisiaj – zdobywający popularność w szalonym tempie.

Jednak nie ma co się temu dziwić – wydajność jest znacznie wyższa niż najpopularniejszej kobyły (czyt: Apache). No i fakt, że jest produkcji rosyjskiej – już któryś raz z kolei o tym wspominam, a jest to kolejny program potwierdzający regułę. :)

Podczas realizacji jednego projektu nadeszła konieczność postawienia demona dla dość obciążonego serwisu. Wybór pierwotnie padł na YAWS, jednak odpadł on z jednego powodu – nie zapewnia prawidłowej obsługi protokołu FastCGI. Owszem, pod CGI wszystko działało jak najbardziej OK, ale wykorzystanie CGI ma dość uciążliwą wadę – uniemożliwia skorzystanie z akceleratorów, a to z powodu braku współdzielonej pamięci.

Pozostało użyć jakiegoś innego demona, który zapewniałby wydajność na podobnym poziomie. No i wybór padł na Nginx.

Ach, przydałoby się jeszcze wspomnieć o systemie operacyjnym (perfidne, nie? ;)). Oczywiście FreeBSD. Jest to chyba system nie do zdarcia; OS z szatańskimi rogami w herbie chyba ani razu mnie nie zawiódł, bez problemu znosząc moje katusze. Podczas obserwacji różnych serwisów zajmujących się bezpieczeństwem, bardzo łatwo dostrzec różnicę w ilości dziur wykrytych w Linuksie oraz FreeBSD.

FastCGI

Nie ma co ukrywać – najbrudniejszą robotą jest w tym wszystkim zmuszenie serwera do współpracy z PHP poprzez protokół FastCGI. Dlaczego najbrudniejszą? Otóż proces nasłuchujący trzeba najpierw wystartować. Kilka lat temu było to nieco uciążliwe, a to za sprawą braku odpowiednich narzędzi. Konieczne było klepanie skryptów startujących.

Dzisiaj jednak mamy do dyspozycji narzędzie spawn-fcgi, które wykonuje za nas całą czarną robotę. Wystarczy wywołać jedno polecenie, a ono bez problemu wystartuje demony w trybie FastCGI, stworzy plik będący potokiem komunikacyjnym do procesu, czy też zadba o odpowiednie uprawnienia dla interpretera. Przyznam, że byłem zaskoczony możliwościami tego narzędzia i z czystym sumieniem mogę stwierdzić, że sprawuje się ono doskonale. Najciekawsze jest jednak to, że pochodzi ono… z konkurencyjnego demona LightTPD. ;)

Ostatnio dowiedziałem się, że jest rozwijany alternatywny projekt PHP-FPM, który ma być – w założeniach – menedżerem procesów FastCGI dla PHP. Nie miałem jednak (jeszcze) okazji go testować, ale projekt zapowiada się obiecująco.

Ach, zapomniałem – wszystkie narzędzia są dostępne z systemu portów naszego systemu. Kawka/herbatka, dostęp do shella i jedziemy. ;)

instalacja

Filozofia instalacji oprogramowania z portów jest całkiem prosta: zazwyczaj w katalogu /usr/ports jest dostępne drzewo tzw. portów (jeśli tam nic nie ma, trzeba je ręcznie pobrać). Wyszukiwanie? whereis nazwa i się dowiemy. ;) Po przejściu do katalogu z interesującym oprogramowaniem wystarczy make config install clean.

PHP

Zaczniemy od samego interpretera. Przyznam, że paczka została nieźle przygotowana. Wszystko jest w katalogu /usr/ports/lang/php5. make config i upewniamy się, że obsługa FastCGI jest uaktywniona. I tu muszę zaznaczyć jedną dość istotną rzecz: domyślne opcje są dobrane pod kątem bezpieczeństwa i jest uaktywniony Suhosin Patch oraz wyłączone wszystkie rozszerzenia przez przełącznik –disable-all. Powoduje to, że niektóre funkcje oznaczone w dokumentacji jako dostępne domyślne – zostaną wyłączone. Pozostaje więc edycja pliku Makefile i wycięcie tego przełącznika, albo (co polecam) dopisanie odpowiedniego –enable-x do linii konfiguracyjnej. Dzięki temu skompilowane zostanie tylko to, czego naprawdę potrzebujemy.

Osobiście korzystam z takiej zawartości zmiennej CONFIGURE_ARGS:

CONFIGURE_ARGS= \
--with-layout=GNU \
--with-config-file-scan-dir=${PREFIX}/etc/php \
--disable-all \
--enable-libxml \
--with-libxml-dir=${LOCALBASE} \
--with-mysql \
--with-mysqli \
--with-curl \
--with-zlib \
--with-iconv \
--with-gd \
--with-jpeg-dir=/usr/local/lib \
--with-pdo-mysql \
--with-pcre-regex \
--with-bz2 \
--with-mbstring \
--enable-simplexml \
--enable-xmlreader \
--enable-xmlwriter \
--enable-xml \
--enable-reflection \
--enable-session \
--enable-pdo=static \
--enable-filter \
--enable-json \
--enable-spl \
--with-mcrypt \
--program-prefix=""

Po zapisaniu wydajemy polecenie make install clean i po pobraniu, kompilacji wszystko powinno być dostępne. Sprawdź wykonując php-cgi -v. Jeśli zostanie wyświetlony numer wersji – wszystko jest jak najbardziej OK. :) Teraz wystarczy stworzyć plik php.ini i umieścić go w katalogu /usr/local/etc.

spawn-fcgi

No tu nie ma się do czego przyczepić – make install clean w katalogu /usr/ports/www/spawn-fcgi i tyle.

nginx

Demon znajduje się w katalogu /usr/ports/www/nginx. make install, zmiana konfiguracji (ekran pokazuje się zawsze przy pierwszej próbie instalacji; domyślne opcje będą w 99% wystarczające), enter. Wszystko. ;)

Upewnij się tylko, czy w pliku /etc/rc.conf widnieje wpis nginx_enable=”YES”. Sprawi on, że przy każdym starcie systemu zostanie uruchomiony również Nginx, na czym nam zależy.

Wykonanie /usr/local/etc/rc.d/nginx start i wpisanie do paska adresu przeglądarki adresu IP serwera powinno zaowocować wyświetleniem strony testowej Nginksa.

Konfiguracja PHP pod FastCGI

Nie będę się skupiał na niuansach pliku konfiguracyjnego Nginx, opiszę tylko to, czego potrzebujemy, aby nakłonić demon do współpracy z PHP. Najpierw musimy jednak wystartować procesy PHP, które będą oczekiwały na żądania ze strony serwera WWW.

Demony we FreeBSD zostały tak przygotowane, aby dało się nimi centralnie zarządzać. Tak samo jest i w przypadku spawn-php. Otwieramy plik /etc/rc.conf w jakimś edytorze (ja korzystam z ee) i dopisujemy do niego:


spawn_fcgi_enable="YES"

Jeśli nie potrzebujemy dodatkowych opcji, typu zmiana liczby procesów-dzieci interpretera (zbyt niska ilość spowoduje błędy 408 i 50x zamiast pożądanej strony), możemy na tym skończyć. Pełną listę opcji, które możemy zmienić, znajdziemy w pliku /usr/local/etc/rc.d/spawn-fcgi:

: ${spawn_fcgi_enable="NO"}
: ${spawn_fcgi_app="/usr/local/bin/php-cgi"}
: ${spawn_fcgi_app_args=""}
: ${spawn_fcgi_pidfile="/var/run/spawn-fcgi.pid"}
: ${spawn_fcgi_username="www"}
: ${spawn_fcgi_groupname="www"}
: ${spawn_fcgi_chroot_dir=""}
: ${spawn_fcgi_bindaddr="127.0.0.1"}
: ${spawn_fcgi_bindport="8118"}
: ${spawn_fcgi_bindsocket=""}
: ${spawn_fcgi_bindsocket_mode="0777"}
: ${spawn_fcgi_children="16"}
: ${spawn_fcgi_max_requests="1000"}
: ${spawn_fcgi_web_server_addrs=""}
: ${spawn_fcgi_allowed_env=""}
: ${spawn_fcgi_path_env="/sbin:/bin:/usr/sbin:/usr/bin:/usr/games:/usr/local/sbin"

Bardzo łatwo jest się domyśleć, że w celu nadpisania którejś z domyślnych zmiennych, wystarczy dopisać do pliku rc.conf nową wartość, a zostanie ona uwzględniona, np. spawn_fcgi_bindport=”8282″.

Teraz wystarczy uruchomić nasz skrypt poleceniem /usr/local/etc/rc.d/spawn-fcgi start. Jeśli ujrzymy komunikat:

Starting spawn_fcgi.
spawn-fcgi: child spawned successfully: PID: XXXX

To oznacza, że wszystko jest w porządku i można przystąpić do właściwej konfiguracji serwera.

Nginx i jego bebechy

W domyślnym pliku konfiguracyjnym nie będziemy grzebać za wiele; potrzebujemy zmienić tylko następujące linijki:

location / {
index index.php;
root /var/www/public_html;
}

# pass the PHP scripts to FastCGI server listening on 127.0.0.1:9000
#
location ~ \.php$ {
include /usr/local/etc/nginx/fastcgi_params;
fastcgi_pass 127.0.0.1:8282;
fastcgi_index index.php;
}

Za wiele do roboty nie jest. Teraz objaśnienia:

  1. Najpierw zmieniamy domyślny plik, którego demon poszukuje w przypadku, gdy odwiedzający otwiera stronę główną.
  2. Katalog na serwis oczywiście też wypada podać. ;)
  3. Następna sekcja odpowiada za komunikację serwera z procesami FastCGI. Podajemy hosta (w 99,99% przypadków 127.0.0.1) oraz port, który wskazaliśmy w konfiguracji spawn-fcgi, bądź domyślny (patrz: wcześniejszy listing).
  4. Linijka wcześniej załącza plik, w którym są zadeklarowane pewne zmienne niezbędne w sterowaniu procesem PHP.
  5. No i ponownie domyślny dokument. ;)

Czy to wszystko? Restart demona (/usr/local/etc/rc.d/nginx restart). ;)

tuning piaskownicy oraz zabawki

przepychacz do rur

Praktycznie nigdzie nie wspomina się o jednej sytuacji, z którą musiałem się zmagać – mianowicie, ze zbyt małym rozmiarem bufora żądania danych HTTP. Na ogół powyższa konfiguracja powinna działać bez zarzutu, jednak niektóre serwisy będą sypały błędami. Dotyczy to skryptów, które wysyłają dużą ilość ciasteczek, ale przy odesłaniu przez przeglądarkę nie przechodza one już do PHP. Rozwiązaniem jest edycja pliku fastcgi_params oraz dopisanie:

fastcgi_connect_timeout 60;
fastcgi_send_timeout 180;
fastcgi_read_timeout 180;
fastcgi_buffer_size 128k;
fastcgi_buffers 4 256k;
fastcgi_busy_buffers_size 256k;
fastcgi_temp_file_write_size 256k;
fastcgi_intercept_errors on;

Po restarcie serwera nie powinno być już błędów.

mod_rewrite

O ile w przypadku mod_rewrite w formacie Apache powiedziane zostało praktycznie wszystko, to w przypadku alternatywnych demonów są pewne problemy – inny format oraz brak obsługi plików htaccess. Jest to jednocześnie wadą i zaletą – nie można dynamicznie zmieniać reguł, ale serwer nie szuka każdorazowo nadpisań konfiguracji.

Przenosząc pewien serwis trafiłem przypadkiem na konwerter regułek.

koniec?

Właściwie tak. ;) Wypadałoby podać jeszcze ciekawe strony, do których warto się odnieść. Doświadczeniami z praktyki się podzieliłem, teraz trochę linków:

10 komentarzy

dopisz swój :: trackback :: RSS z komentarzami

RSS z komentarzami :: trackback

Skomentuj

Możesz używać znaczników XHTML. Dozwolone są następujące tagi: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <s> <strike> <strong> <pre lang="" line="" escaped="" cssfile="">

Wszystkie komentarze przechodzą przez moderację oraz filtry antyspamowe. Nie zostanie opublikowany komentarz, jeśli:

  • Jego treść obraża kogokolwiek.
  • W treści znajdują się wulgaryzmy i słownictwo ogólnie uznane za nieprzyzwoite.
  • Mam wątpliwości co do autora wpisu (Wszelkie anonimy są kasowane - niezależnie od zawartości - wpisz prawdziwy e-mail. Jeśli usunąłem, Twoim zdaniem, komentarz niesłusznie - daj znać). Zdarza się, iż sprawdzam kim jest komentujący.
  • Zawiera jakąkolwiek formę reklamy.

Warning: Undefined variable $user_ID in /usr/home/er1zpl/domains/eriz.pcinside.pl/public_html/weblog/wp-content/themes/inBlueDiary/comments.php on line 112

Szufladka