Dziesiąty artykuł z cyklu Konfigurujemy VPS. Dorzucę jeszcze parę słów na temat konfiguracji nginx-a (której podstawy opisałem w częściach siódmej i ósmej).
Tym razem jest to mniej uporządkowany spis rozmaitości, od dyskusji o liczbie obsługiwanych połączeń, po wzmianki o różnych ciekawych modułach.
Spora część poniższych informacji wykracza poza ramy cyklu Konfigurujemy VPS, przy stawianiu małego serwisu albo bloga większość tego artykułu można swobodnie pominąć.
Numerki, numerki, numerki
Ze względu na swój sposób działania, procesy nginx-a otwierają równocześnie wiele plików i gniazd. Można tu napotkać na ograniczenia z kilku poziomów działania programu i systemu operacyjnego.
Liczba połączeń
W pliku /etc/nginx/nginx.conf
definiowana jest maksymalna ilość
połączeń sieciowych realizowanych przez każdy z procesów:
events {
worker_connections 1024;
}
Parametr ten obejmuje nie tylko połączenia przychodzące ale także wychodzące - do proksowanych serwerów backendowych, do procesów FastCGI, do serwerów memcached itp. To jest ograniczenie na ilość otwartych gniazd, niezależnie od ich rodzaju!
Ograniczenie to obowiązuje per-proces, jeśli nginx uruchamia kilka procesów roboczych, każdy z nich ma osobną taką pulę.
Ilość procesów roboczych
nginx może być uruchamiany w konfiguracjach wieloprocesowych. Pozostaje wówczas programem zdarzeniowym, każdy z procesów obsługuje wiele połączeń równocześnie - ale takich procesów jest kilka, czasem kilkanaście.
Ilość procesów ustawiamy przy pomocy dyrektywy:
worker_processes 1;
w głównym pliku konfiguracyjnym.
Kiedy warto ustawić więcej niż 1?
Oczywisty powód to wykorzystywanie maszyny wieloprocesorowej
(lub wielordzeniowego procesora). W takim wypadku (zwłaszcza, gdy
nginx jest główną aplikacją na maszynie), można ustawić
worker_processes
na liczbę procesorów/rdzeni (czyli np. na 4
przy dwóch dwurdzeniowych procesorach).
nginx
ma też możliwość wiązania poszczególnych procesów z konkretnymi procesorami/rdzeniami:worker_processes 4; worker_cpu_affinity 0001 0010 0100 1000;
(maszyna 4-rdzeniowa, każdy proces dostaje własny rdzeń) albo:
worker_processes 2; worker_cpu_affinity 0101 1010;
(także maszyna 4-rdzeniowa ale tylko dwa procesy, każdy może działać na dwóch rdzeniach). Rzadko jest to potrzebne, scheduler systemu operacyjnego radzi sobie poprawnie i bez takiego wsparcia.
Przy strojeniu pod duże obciążenia zwiększenie liczby procesów roboczych może być też korzystne ze względu na mniejszy wpływ blokowania się na dostępach do dysku.
Optymalna konfiguracja zależy od konkretnej instalacji. Na niezbyt mocno obciążonym VPSie spokojnie wystarczy jeden proces. Na silnych maszynach serwujących duże ilości plików może być ich kilkanaście.
Ograniczenia ilości otwartych plików
Okazyjne (pod dużym obciążeniem lub benchmarkiem) błędy: too many
open files
, np:
2008/11/17 02:15:02 [alert] 21748#0: accept() failed
(24: Too many open files) while accepting new connection
oznaczają przekroczenie liczby otwartych deskryptorów (w konfiguracji
VPSowej mało prawdopodobne). Ograniczenie to może wynikać z
konfiguracji systemowej (/etc/security/limits.conf
), wywołania
ulimit
przed uruchomieniem nginx
-a albo konfiguracji samego
nginx
-a.
Podstawowa metoda strojenia (gdy nginx
jest uruchamiany z konta root
)
to parametr:
worker_rlimit_nofile 8192;
(umieszczany na głównym poziomie nginx.conf
). Alternatywnie można
wykorzystać ulimit
(np. ulimit -S -H -n 8192
) przed uruchomieniem
nginx
-a albo odpowiednio przeedytować parametr nofile
w pliku
/etc/security/limits.conf
. 8192 to przykładowa, zwykle wystarczająca
wartość (powinna przewyższać sumę worker_connections
i otwartych plików
logów).
To ilu równoczesnych klientów w końcu obsłużymy
Teoretyczne maksimum to worker_processes * worker_connections
.
Trzeba jednak pamiętać, że przeglądarka zwykle otwiera dwa połączenia
(a nie jedno), a o ile stosujemy reverse-proxy, FastCGI lub
inną zbliżoną technikę, będziemy wykorzystywać połączenia
backendowe. Dlatego pesymistyczne oszacowanie to worker_processes *
worker_connections / 4
.
Oczywiście to dotyczy tylko limitu nawiązanych połączeń. Ile naprawdę obsłużymy zależy przede wszystkim od przepustowości połączenia sieciowego oraz wydajności maszyny. Tu odpowiedzią może być tylko benchmark.
SSL
Nginx obsługuje SSL. Nie dzieje się tu nic specjalnego, piszemy:
server {
listen www.naszserwer.pl:443;
ssl on;
ssl_certificate /ścieżka/do/www.naszserwer.pl.cert;
ssl_certificate_key /ścieżka/do/www.naszserwer.pl.key;
keepalive_timeout 60;
...
}
Celowo zamieściłem keepalive_timeout
, przy używaniu SSL
aktywne keepalive
jest zdecydowanie zalecane.
Jeśli ta sama treść jest serwowana zarówno po http
, jak po https
,
wygodne jest wydzielenie reguł obsługi do osobnego pliku przy
pomocy include
.
Mamy standardowy, zbliżony do Apache, pakiet opcji SSL (min. wybór szyfrów czy weryfikacja certyfikatów klienckich). Patrz dokumentacja modułu.
Kontrola dostępu
Nginx obsługuje typowe reguły dostępu oparte na adresach IP, a także autoryzację hasłami HTTP.
Dostęp dla wybranych IP
Klauzule allow
i deny
, podające adresy IP (pojedyncze lub
grupowe). Klauzule są sprawdzane w kolejności w jakiej
są napisane, obowiązuje pierwsza pasująca.
Przykład:
location /statystyki/ {
alias /var/data/webstats/;
allow 211.84.32.121;
deny 62.99.75.37;
allow 62.99.75.0/24;
deny all;
autoindex on;
}
Powyższy przykład pozwala na dostęp 211.84.32.121
(np. maszyna
domowa) oraz wszystkim maszynom z sieci 62.99.75.*
za wyjątkiem
62.99.75.37
.
Autoryzacja hasłem
Prosta autoryzacja HTTP Basic.
location /admin/ {
auth_basic "Admin area password";
auth_basic_user_file /etc/nginx/htpasswd;
}
Plik htpasswd
ma ten sam format, co w przypadku Apache, można
go tworzyć i aktualizować przy pomocy pochodzącego z Apache
programu htpasswd
.
Ten rodzaj autoryzacji nadaje się do stosowania wyłącznie po SSL lub w zaufanej sieci lokalnej. HTTP Basic przesyła hasło jawnie, może ono zostać podsłuchane.
Inne niż plik htpasswd
metody weryfikacji haseł zapewnia
nieoficjalny dodatek
ngx_http_auth_pam_module.
Skomplikowane reguły proxy
W poprzednim artykule dałem prościutki przykład konfiguracji reverse-proxy. Można go zmienić w znacznie ciekawszy.
Upstream
Przerabiając wyłącznie dyrektywę upstream
możemy dystrybuować
ruch między kilku maszynami. Na przykład:
upstream moj_backend {
server 192.168.1.100:8080;
server 192.168.1.101:8080;
}
sprawi, że nginx
będzie rozrzucał żądania - po równo (round-robin) -
między dwoma serwerami, a gdy któryś z nich ulegnie awarii, skieruje
cały ruch do pozostałego. Albo:
upstream moj_backend {
server app1.mojadomena.pl:5000
weight=5 fail_timeout=10s max_fails=3;
server app2.mojadomena.pl:5001
weight=2 fail_timeout=10s max_fails=2;
server app3.mojadomena.pl:5000
backup;
}
gdzie app1
będzie dostawał więcej żądań niż app2
(mniej więcej 2.5
raza więcej), app1
zostanie uznany za nie działający jeśli nie
odpowie na trzy żądania w ciągu 10 sekund, wreszcie app3
będzie
wykorzystywany tylko gdy zarówno app1
, jak app2
nie działają.
Parametrów jest więcej, patrz opis modułu upstream.
Interesującym uzupełnieniem spoza oficjalnej dystrybucji jest moduł UpstreamFair, inteligentnie wybierający najmniej obciążony backend.
Inny rodzaj zastosowań obsługuje UpstreamHash, pozwalający wybierać jeden z backendów na podstawie charakterystyk żądania (jedno z zastosowań to kierowanie klienta zawsze do tego samego backendu).
Nagłówki HTTP
Nginx domyślnie przekazuje do backendu wszystkie nagłówki HTTP tak, jak je otrzymał, z dwoma wyjątkami:
Host:
jest ustawiane na nazwę danego backendu,Connection:
jest ustawiane naclose
Jeśli chcemy, by backend otrzymywał orginalną nazwę maszyny docelowej
w Host
, możemy napisać:
location /app/ {
proxy_pass http://moj_backend/;
proxy_set_header Host $host;
proxy_set_header X-Forwarded-For
$proxy_add_x_forwarded_for;
};
Przy okazji dałem przykład ustawiania X-Forwarded-For
(zmiennej
używanej niekiedy przez przykryte przez proxy aplikacje).
W drugą stronę, nginx
zastępuje zwrócone nagłówki Date:
i Server:
oraz
usuwa X-Pad
i X-Accel-*
. Inne nagłówki można ukryć explicite:
location /app/ {
proxy_hide_header X-AspNet-Version; # ha ha
};
Timeouty
Można ustawić całą serię timeoutów związanych z komunikacją
z proxy, np. proxy_connect_timeout
na połączenie się z (re)startowanym
backendem, czy proxy_send_timeout
na przekazanie całego żądania.
Domyślne wartości rzadko wymagają korekty.
Jedyną, którą często trzeba modyfikować, jest proxy_read_timeout
:
location /app/ {
proxy_pass http://moj_backend/;
proxy_read_timeout 90;
};
Jest to maksymalny czas oczekiwania na odpowiedź od serwera
aplikacyjnego. Jeśli zdarzają się nam długo liczące się zapytania czy
raporty, trzeba powyższy parametr odpowiednio dopasować (zadając
wartość wyższą niż maksymalny normalny czas realizacji żądania) -
inaczej nginx
zgłosi użytkownikowi błąd.
Buforowanie
nginx
domyślnie buforuje odpowiedzi backendów przed odesłaniem ich
do przeglądarki (tj. agreguje odpowiedź i dopiero gotową odsyła). Mamy tu
całą serię parametrów pozwalających kontrolować czy/kiedy buforować,
do jakiego rozmiaru buforować w pamięci a od jakiego zrzucać na dysk
itd. Szczegółowy opis można znaleźć w dokumentacji modułu
proxy. Wspomnę tylko o dwóch sprawach.
Miejsce na dysku, gdzie są odkładane tymczasowe pliki, wybieramy tak:
location /app/ {
proxy_pass http://moj_backend/;
proxy_temp_path /var/nginx/proxytmp;
};
Z kolei wpis w logu taki jak:
2008/12/27 00:00:07 [warn] 1444#0: *19 an upstream
response is buffered to a temporary file (...)
jest nieszkodliwy, oznacza tylko, że odpowiedź była za duża, by zmieścić się w buforze pamięciowym. Jeśli pojawia się tego bardzo dużo, warto przemyśleć konfigurację (zwiększyć rozmiar buforów albo wyłączyć buforowanie) - jest to dodatkowy koszt wydajnościowy. W skromniejszych instalacjach nie trzeba się tym przesadnie przejmować.
Zapis do logów
Kilka możliwości dopracowania logowania.
Selektywne wyłączanie
Bardzo użyteczny mechanizm: selektywne wyłączanie logowania. Na przykład:
location ~* ^.+\.(jpg|png|gif|ico)$
{
access_log off;
expires 30d;
}
wyłącza logowanie (w access.log
) informacji o pobieraniu
obrazków.
Podobnie można wyłączyć logowanie niektórych błędów:
location = /favicon.ico {
log_not_found off;
}
Różne logi dla różnych aplikacji
Dyrektywa access_log
może być umieszczana nie tylko
w blokach http
i server
, ale też w blokach location
.
Daje to dużą elastyczność, w szczególności każda z aplikacji
może mieć własny log.
Można pisać do kilku logów naraz (np. w różnych formatach).
W developerskiej linii nginx-a (od wersji 0.7.4) pojawiła się możliwość używania w nazwie pliku loga zmiennych związanych z żądaniem (np. nazwy serwera). Stosując ten mechanizm trzeba zachować pewną ostrożność - o ile nie jest ustawione
open_log_file_cache
, nginx przy każdym żądaniu otwiera i zamyka plik logu.
Własne formaty
Domyślnym formatem access-logu jest combined
.
Podobnie jak w przypadku Apache, można definiować własne formaty.
Np. (to jest jedna linijka):
log_format extended '$remote_addr - - [$time_local]
"$request" $status $body_bytes_sent "$http_referer"
"$http_user_agent" "$http_host" $request_time
"$http_x_forwarded_for" "$http_via" "$gzip_ratio"';
z czego potem korzystamy pisząc:
access_log /var/log/nginx/moj.log extended;
Szczegóły - patrz opis modułu.
Buforowanie
Buforowanie zapisów do logu (zamiast zapisywać wszystko od razu,
nginx
zbiera większe paczki):
access_log /var/log/nginx/access.log combined buffer=32k;
Parametr buffer
nie powinien przekraczać rozmiaru bloku zapisywanego
na dysk jedną operacją write
. Wszystkie znane mi przykłady, w których
buforowanie w ogóle jest włączone, stosują powyższe 32 kB.
Logowanie żądań pomocniczych
W linii developerskiej nginx
-a (od wersji 0.7.18) pojawiła
się opcja
log_subrequests on;
pozwalająca zapisywać w access.log
-u żądania pomocnicze (stosowane
w wielu wypadkach z rewrite
na czele).
Warunkowe przekierowania do backendu
Przy używaniu reverse-proxy a także FastCGI dość popularne są sztuczki typu jeśli istnieje plik o zadanej nazwie, zaserwuj go, jeśli nie, przekaż żądanie do aplikacji.
Tradycyjna metoda:
root /var/www;
location / {
log_not_found off;
error_page 404 = @cms;
}
location @cms {
internal;
# ... parametry FastCGI (albo proxy)
}
W ten sposób przy żądaniu - powiedzmy - /static/style.css
,
nginx najpierw sprawdzi czy istnieje plik /var/www/static/style.css
,
a jeśli nie, spyta o niego PHP-ową aplikację.
Nazwy typu
@cms
to popularyzująca się ostatnio konwencja nazewnicza dla określania wewnętrznych lokacji. Nie jest w żaden sposób wymagana, po prostu znak@
niemal nigdy nie występuje w normalnych adresach.
W najnowszych developerskich wersjach nginx-a (0.7.27 i nowsze)
testowany jest bardziej elegancki mechanizm, zmienna try_files
:
location / {
try_files $uri $uri/index.html @cms;
}
(sprawdź po kolei wybrane pliki, zwróć pierwszy istniejący). Szczegółowa semantyka jeszcze jest dopracowywana.
Wybrane optymalizacje wydajnościowe
Kilka technik optymalizacyjnych.
Memcached
Nginx potrafi współpracować z memcached
, czyli zwracać
strony zapisane w buforach memcached
. Jest to na razie
bardzo prosty mechanizm wymagający kooperacji z backendem,
w typowym scenariuszu nginx
próbuje pobrać stronę z bufora
a w razie błędu pobiera dane z backendu:
location / {
set $memcached_key $uri;
memcached_pass name:11211;
default_type text/html;
error_page 404 = @backend;
}
location = @backend {
proxy_pass moj_backend;
}
Backend powinien tu nie tylko zwrócić stronę ale i zapisać ją w
memcached
, dbając o poprawny czas ważności i klucz.
Wykorzystywanie memcached
to dość złożona tematyka, w tym
artykule nie będę jej dalej rozwijał.
Ciekawy moduł zewnętrzny z bardziej zaawansowaną obsługą memcached: ngx_upstream_memcached_hash.
proxy_store
Scenariusz, w którym wybrane - nie zmieniające się - zasoby chcemy kopiować z backendu i serwować bezpośrednio. Zbliżony do ręcznego skopiowania ale nieraz wygodniejszy dystrybucyjnie (np. instalujemy nową wersję aplikacji z jej grafikami i stylami, a nginx automatycznie je kopiuje i potem serwuje).
Wygląda to tak:
location /img/ {
root /var/cached/myapp;
error_page 404 = /fetch$uri;
}
location /fetch {
internal;
proxy_pass http://182.163.21.1:80;
proxy_store on;
proxy_store_access user:rw group:rw all:r;
proxy_temp_path /var/data/myapp;
alias /var/cached/myapp/img/;
}
nginx
po otrzymaniu żądania pobrania /img/mojelogo.png
spróbuje
je zaserwować z /var/cached/myapp/img/mojelogo.png
, a jeśli go tam
nie znajdzie, pobierze je z backendu i zapisze na przyszłość.
Uwagi:
root
z głównej dyrektywy ialias
z pomocniczej muszą być dopasowane,- katalog tymczasowy proxy (
proxy_temp_path
) musi być na tym samym systemie plików, co trwale zapisywane kopie (nginx
ściąga plik doproxy_temp_path
a potem zmienia mu nazwę), proxy_store
może zadawać konkretny katalog (on
domniemuje odpowiedni na podstawiealias
).
Kompresja w locie
Dyrektywy gzip
zapewniają kompresję w locie (o ile
przeglądarka klienta ją obsługuje) - podobną jak
mod_deflate
realizuje dla Apache. Efektem jest oszczędność
pasma i - zazwyczaj - szybsze (w poczuciu użytkownika) działanie
serwisu.
Ważna cecha nginx
-a to gzip_proxied
, możliwość kompresji
treści zwracanych przez aplikacje przykryte reverse proxy.
Przykładowa konfiguracja:
http {
# ...
gzip on;
gzip_min_length 1024;
gzip_proxied any;
gzip_vary on;
gzip_types text/plain text/html
text/css application/x-javascript
application/xml application/xml+rss;
}
gzip_types
pozwala kompresować pliki inne niż domyślne HTML.
gzip_proxied
można też ustawiać inaczej, np.
gzip_proxied expired no-cache no-store private auth;
będzie kompresować tylko pliki, które na pewno nie są cacheowane przez przeglądarkę lub publiczne proxy (cel: uniknięcie inwalidacji tych cache ze względu na kompresję).
Dyskusja szczegółowych konsekwencji (ma znaczenie jeszcze gzip_vary
i błędy IE<=6) wykracza już zdecydowanie poza zakres tego cyklu, w
każdym razie: dla w pełni dynamicznych treści gzip_proxied
jest
przydatne i zalecane.
Jeśli backend obsługuje kompresję sam z siebie, a używamy
gzip_proxied
, jest ona niepotrzebna. Informację dla backendu by nie kompresował zgłaszamy robiąc:proxy_set_header Accept-Encoding "";
w odpowiedniej dyrektywie
location
.
Więcej parametrów kompresji: patrz dokumentacja.
Prekompresowane pliki
Dyrektywa gzip_static
pozwala uniknąć wielokrotnej kompresji
tych samych plików. Gdy jest włączona i przeglądarka obsługuje
kompresję, nginx
przed zwróceniem pliku
ścieżka/do/plik.html
sprawdzi, czy na dysku
nie ma ścieżka/do/plik.html.gz
. Jeśli jest (i daty modyfikacji
się zgadzają), zwróci go zamiast kompresować w locie plik.html
.
Włączanie:
http {
# ...
gzip_static on;
gzip_vary on;
}
Nieoficjalny moduł pozwalający przechowywać skompresowane pliki w memcached: MemcachedGzip.
Nagłówki cacheowania
Standardowe dyrektywy pozwalające na cacheowanie po stronie klienta,
tj. ustawiające nagłówki Expires
i Cache-Control
.
location /img {
expires 24h;
}
(obrazki ważne przez dobę od chwili pobrania) albo:
location /css {
expires max;
}
(style ważne 10 lat). Ten drugi zapis oczywiście trzeba połączyć ze zmianą nazwy pliku przy każdej istotnej edycji.
Nginx generuje też ETag
, to nie wymaga żadnej konfiguracji.
Empty GIF
Miły drobiazg:
location = /img/empty.gif {
empty_gif;
}
Pusty plik .gif
zostanie zwrócony bez zaglądania na dysk.
Puste obrazki są obecnie mniej popularne w layoutach stron niż było to parę lat temu, ale ten sam mechanizm można stosować w każdym przypadku gdy musimy zwrócić sukces ale nieważne, co zwracamy (np. URL używany przez jakiś program monitorujący do sprawdzania, czy nasz serwer działa). Jest to bardzo szybka i tania metoda zwrócenia czegoś.
W takich lokacjach często przydaje się też opisywane wyżej
access_log off
.
FastCGI przez unix socket
Opisywałem poprzednio konfigurację FastCGI opartą o port TCP. Zamiast niego można wykorzystać unix socket. Może być to korzystne ze względów bezpieczeństwa (unix socket jest z definicji dostępny tylko lokalnie), spotkałem też opinie, że daje niewielką korzyść wydajnościową.
Zmiana?
Korygujemy skrypt uruchamiający program FastCGI, zastępując parametry
-a
i -p
(adres i numer portu) przez -s
(ścieżka do
Unix-socketu). Omawiany poprzednio skrypt oparty o spawn-fcgi
przyjmie taką postać:
#!/bin/sh
CHILD_COUNT=4
SOCKET=/var/www/tmp/php-fastcgi.socket
USER=www-data
GROUP=www-data
exec /usr/bin/spawn-fcgi -f /usr/bin/php-cgi \
-s $SOCKET \
-P /var/run/fastcgi-php.pid \
-u $USER -g $GROUP \
-C $CHILD_COUNT \
-n
W konfiguracji nginx
-a natomiast zmieniamy fastcgi_pass
, np
zamiast dotychczasowego fastcgi_pass 127.0.0.1:54217
piszemy:
fastcgi_pass unix:/var/www/tmp/php-fastcgi.socket
Restartujemy oba komponenty.
Higiena
Kilka wskazówek higienicznych.
Strona trwa upgrade
Sztuczka pozwalająca łatwo obsługiwać czasowe wyłączanie serwisu i podobne sytuacje:
if (-f $document_root/przerwa.html) {
return 503;
}
error_page 503 @503;
location @503 {
rewrite ^(.*)$ /przerwa.html break;
}
Jeśli plik przerwa.html
istnieje (w katalogu ustawionym jako root
),
w odpowiedzi na dowolne żądanie zostanie wyświetlona jego treść (wraz
z kodem HTTP 503 Service unavailable
, poprawnie rozumianym przez
boty google i inne sieciowe aplikacje).
Z taką konfiguracją, zaczynając upgrade po prostu wgrywamy plik
przerwa.html
(z odpowiednim wyjaśnieniem) i już. Wykonujemy niezbędne
prace, a na koniec plik usuwamy.
Ukrycie wersji serwera
Jedna z prostych dobrych praktyk - chowamy informacje o szczegółowej wersji naszego serwera. Normalnym użytkownikom nie są potrzebne, potencjalnym włamywaczom nie ma powodu ułatwiać pracy.
http {
# ....
server_tokens off;
}
Efekty są widoczne np. na stronie błędu.
Strony błędów dostępne tylko w razie błędów
Nie ma powodu, by strony błędów były normalnie dostępne.
server {
# ...
error_page 502 503 504 /error/50x_error.html;
location /error/50x_error.html {
internal;
}
}
W ten sposób strona 50x_error.html
zostanie wyświetlona w razie
błędu ale nie da się jej otworzyć explicite.
Ciekawostki
Status
Prosta informacja o statusie przetwarzania, użyteczna np. przy dopinaniu zewnętrznych programów monitorujących:
location /status {
stub_status on;
access_log off;
allow 127.0.0.1;
deny all;
}
Przykładowy efekt (to jest prosty tekst, łatwy do parsowania):
Active connections: 72
server accepts handled requests
490523 490523 672377
Reading: 67 Writing: 1 Waiting: 4
Active connections
to ilość aktualnie nawiązanych połączeń
(obejmuje także połączenia do backendów).
Trzy duże liczby to sumaryczna statystyka procesu, kolejno: ilość
przyjętych połączeń, ilość obsłużonych połączeń (byłaby mniejsza od
pierwszej gdyby jakiś klient zamknął połączenie nie czekając na
odpowiedź) oraz ilość obsłużonych żądań (większa od ilości połączeń
jeśli stosujemy keepalive
i w ramach niektórych połączeń było więcej
niż jedno żądanie).
Reading
to ilość połączeń, w których nginx
aktualnie czyta żądanie
(dokładniej: odbiera nagłówki HTTP), Writing
to ilość połączeń w
trakcie obsługi (od czytania treści żądania po odsyłanie odpowiedzi),
Waiting
to nawiązane ale w tej chwili nie używane połączenia
keep-alive
(suma tych trzech liczb jest równa liczbie aktywnych
połączeń).
Cookie
Moduł userid zapewnia generowanie (i odczytywanie) cookie identyfikujących użytkownika. Można je wykorzystywać np. w zapisach do logów - albo przekazywać do aplikacji backendowych.
Bezpieczny download
Ciekawostka wprowadzona w wersji developerskiej (od 0.7.18). Użytkownik musi znać tajny URL by pobierać pliki z zadanego katalogu.
Przykład:
location /download/ {
secure_link_secret ToJestTajne;
if ($secure_link = "") {
return 403;
}
}
Zwykłe żądanie - np. http://moj.serwer.pl/download/myfile.zip
-
zostanie odrzucone (mimo obecności myfile.zip
w odpowiednim
katalogu). Uda się http://moj.serwer.pl/download/XXXXX/myfile.zip
,
gdzie XXXXX
jest wyliczane jako md5(link,ToJestTajne)
.
Odrzucenie wynika z powyższego
if
. Mechanizm sam z siebie po prostu ustawia$secure_link
- na link jeśli weryfikacja się powiodła, na wartość pustą jeśli nie.
Jedno z zastosowań to ochrona linków służących do
przekierowań/proksowania (http://moj.sajt.pl/click/XXXXX/jakis.inny.sajt/strona/
).
Drobne problemy i niedogodności
Could not build the server_names_hash
Gdy używamy długich nazw domen (notatnik.mekk.waw.pl
się załapał),
nginx potrafi zgłosić błąd could not build the server_names_hash, you
should increase server_names_hash_bucket_size: 32
(i nie wystartować).
Rozwiązanie:
http {
# ....
server_names_hash_bucket_size 64;
}
Dokumentacja programistyczna
Emiller's Guide to Nginx Module Development dostarcza obszernych informacji na temat wnętrzności nginx-a, a przede wszystkim jest podręcznikiem dla osób chcących pisać lub modyfikować moduły rozszerzające.