Nginx serwer www z obsługą php@FastCGI part I

  • Data: 2011

Nginx to lekki serwer http i reverse proxy. Potrafi także działać jako load balancer, dlatego często określany jest jako router HTTP. Stanowi poważną alternatywę dla przeładowanego apache. W środowisku produkcyjnym nginx zaskakuje wydajnością oraz małym zużyciem pamięci co jest zaletą dla dużych jak wordpress.com jak i małych jak słabiutki vps z 128MB.
Na niekorzyść nginx-a przemawia fakt, braku wsparcia plików .htaccess oraz składnia modułu rewrite jest nieco inna od składni mod_rewrite. Brak obsługi .htaccess determinuje konieczność wprowadzania czy to dyrektyw rewrite czy innych obsługiwanych w .htaccess do konfiguracji serwera przez jego administratora.
Przewagę jaką uzyskuje nginx nad popularnym apachem wynika z modelu obsługi przychodzących połączeń. W Apache każde nowe połączenie wymaga uruchomienia nowego procesu (mpm-prefork) lub wątku (mpm-worker), który obsłuży przychodzące żądanie.
W przypadku nginx-a mamy do czynienia z modelem zdarzeniowym polegającym na obsłudze wielu połączeń przez ten sam proces, który reaguje na takie zdarzenia, jak nowe żądanie od klienta, odpowiedź od serwera aplikacji itp. Jeżeli na jednym połączeniu nic się nie dzieje, proces nginxa może obsługiwać inne, aktywne połączenie. Proces (wątek) Apache'a czeka wtedy bezczynnie.
Nginx tworzy 1-n... procesów (w zależności od potrzeb i sprzętu), każdy z tych procesów, może obsłużyć kilkadziesiąt/set tysięcy połączeń. Pokrótce tyle teorii.

Na początku chcę zaznaczyć, iż nie będę się wdawał w sam proces instalowania nginx-a, wiadomo to już jest uzależnione od dystrybucji (paczki) lub indywidulanej konfiguracji (kompilacji ze źródeł).

  • Globalna konfiguracja serwera:
  • główny plik konfiguracyjny - nginx.conf
  • 
    user www-data;
    worker_processes  1;
    
    error_log  /var/log/nginx/error.log;
    pid        /var/run/nginx.pid;
    
    events {
        worker_connections  1024;
    }
    
    http {
        include       /etc/nginx/mime.types;
        default_type  application/octet-stream;
    
        access_log  /var/log/nginx/access.log;
    
        sendfile        on;
        tcp_nopush     on;
    
        keepalive_timeout  0;
        keepalive_timeout  65;
        tcp_nodelay        on;
    
        gzip  on;
    
        include /etc/nginx/conf.d/*.conf;
        include /etc/nginx/sites-enabled/*;
    }
    
    i krótki opis do tego pliku:
  • user www-data; - konfiguracja z jakimi prawami będzie uruchomiony serwer
  • worker_processes 1; - ilość uruchomionych procesów, tutaj kierować się należy zasadą: ilość rdzeni = ilość procesów (jeżeli jest taka potrzeba)
  • worker_connections 1024; - maksymalna ilość połączeń w ramach 1 procesu
    Dzięki dwóm powyższym parametrom teoretycznie możemy oszacować maksymalną liczbę równocześnie obsłużonych klientów: max_clients = worker_processes * worker_connections , natomiast trzeba pamiętać, że w przypadku serwowania stron dynamicznych np. w php jeden klient otwiera dwa połączenia (FastCGI), i już wtedy: max_clients = worker_processes * worker_connections / 2
    a jeszcze bezpieczniej przez 4.
  • include - cała konfigurację można umieścić w pliku nginx.conf ale dla większej przejrzystości i porządku, szczególnie jeśli jest ona rozbudowana (np. wiele domen) można umieszczać w osobnych plikach.
  • W Debianie i pokrewnych dystrybucjach model rozmieszczenia plików jest zapożyczony z Apache (katalogi: sites-available , sites-enabled).
    Trzymając się konwencji Debiana dodatkową konfigurację oddeleguję do osobnych plików.
  • Nginx serwujący kontent statyczny:
  • stworzmy w /etc/nginx/sites-available plik example a w nim:
  • 
    server {
    	# Dyrektywa określająca adres i/lub port, na których serwer nasłuchuje
    	listen       80;
    	
    	# Dyrektywa przypisująca nazwy wirtualnym serwerom
    	server_name  przyklad.pl www.przyklad.pl;
    	
    	# Logi domeny przyklad.pl
    	access_log  /var/log/nginx/przyklad.access.log; 
    	error_log /var/log/nginx/przyklad.pl.error.log;
            
    		location / {
    		root   ścieżka naszego katalogu ze stroną;
    		index  index.html index.htm;    
    		}  
    
    }
    
  • teraz tworzymy dowiązanie symboliczne: ln -s /etc/nginx/sites-available/przyklad /etc/nginx/sites-enabled/przyklad
  • następnie restart nginx-a: /etc/inid.d/nginx restart
  • Jeśli nie mamy domeny nie używamy wtedy dyrektywy server_name, jeżeli jednak chcemy mieć kilka stron na jednym IP możemy wystawić je na różnych portach:
    
    # strona_1:
    server {
    	listen       80;
    	
    	# ....
    
    		location / {
    		root   /var/www/strona_1;
    		index  index.html index.htm;    
    		}  
    
    }
    # strona_2:
    server {
    	listen       81;
    	
    	# ....
    
    		location / {
    		root   /var/www/strona_2;
    		index  index.html index.htm;    
    		}  
    
    }
    

    W czasie konfiguracji nginx-a natknąłem się na dość kłopotliwą sytuacje. Przedstawię ją na konkretnym przykładzie:
    Wyobraźmy sobie, że mamy domenę example.com, 4 subdomeny: main.example.com, poczta.example.com, users.example.com, qwerty.example.com . Trzy pierwsze są wirtualnymi hostami wykorzystywanymi przez nginx-a natomiast ostania qwerty.example.com nie jest powiązana z żadną konfiguracją wirtualnego hosta. I tu pojawia się problem, gdyż kiedy wpiszemy w przeglądarkę http://qwerty.example.com/ - wtedy wyswietli nam się jedna z tych trzech stron (chyba zależy od kolejności jaką nginx robi include).
    W pliku nginx.conf wstawiamy blok server przed dyrektywami include:

    
    server {
        listen          80 default;
        server_name    _ ; # Catch all
        
        return 444;  # Kod 444 zamyka połączenie bez wysyłania nagłówków.
    }
    

    Oczywiście jest to ułamek możliwości nginx-a, nic nie wspomniałem o konfiguracj reverse-proxy czy silnemu wsparciu wyrażeń regularnych...
  • Nginx z obsługa PHP poprzez FastCGI part II

Powrót »