Není to tak dlouho, co jsme na Rootu psali o lehkém webovém serveru lighttpd. Čtyřdílný seriál, který ukázal, že lighttpd dokáže zastoupit jiná řešení a není to ani moc náročné. Vývoj lighttpd nyní stojí, poslední stabilní verze 1.4.28 byla vydána 22. srpna 2010. Ve své době měl hodně příznivců a třeba servery jako Wikipedia nebo YouTube se svěřily do jeho binárních rukou. Web se „bohužel“ vyvíjí a když nějaký projekt zůstane stát, najde se jiný, který mu ukáže záda. V případě lighttpd by to mohl být Nginx, univerzální, rychlé a bezpečné řešení webového serveru.
K napsání tohoto článku a vůbec nasazení serveru Nginx jako reverzní proxy pro Apache mě inspiroval článek Petra Krčmáře o útoku slow loris. Jednoduchý útok, který už v minulosti potrápil mnoho administrátorů webových serverů. Prostředkem jsou vytvořená spojení, kterými se jako plíživé veverky sune několik bytů dat. Webový server s citlivou architekturou pak netrpělivě čeká na dokončení požadavku, ale ten nepřijde a když narazí na limit počtu spojení, tak to s dalšími požadavky dopadne špatně a budou odmítnuty. Takový server nereaguje a v logu není ani zmínka o tom, že je něco špatně.
Apache takovou citlivou architekturou disponuje a i když použijete třeba mod_antiloris nebo si nastavíte dobře firewall, tak to během slow loris útoku stejně nemusí být ono. V praxi se bohužel bez Apache často neobejdeme. Máte-li webový server jen pro sebe, tak není problém vzít Nginx nebo lighttpd, nastartovat PHP přes FastCGI a spojit to všechno dohromady. U jiných jazyků to funguje samozřejmě podobně. V opačném případě, kdy jsou na serveru různé aplikace s různými požadavky a hlavně různých lidí, nemusí být reálné dát Apache pryč. Pořád disponuje vlastnostmi, na kterých jsou některé aplikace závislé. Nejlepším příkladem je v tomhle modrewrite, bez kterého někdy prostě vlak nejede.
A jsme na pomezí dvou světů. Na jedné straně je uživatel, který třeba i platí a na druhé straně je bezpečnost. Pokud se navíc zamyslíte a uděláte pár testů, tak zjistíte, že Apache není nejefektivnější a když před něj strčíte proxy, tak serveru najednou spadne load o pár desetinek dolů. To znamená, že server bude odpovídat rychleji, a také to, že na něj najednou dostanete třeba o polovinu více webů, a to už začíná být zajímavé.
Nginx jako vstupní brána do Apache
Apache někdy zůstat musí, s tím nic neuděláme, ale určitě bychom ho neměli motat tam, kde je jeho přítomnost zbytečná a někdy dokonce i na škodu. Navíc by se mohlo hodit, když ho schováme na lokální adrese a nebudeme ho ukazovat venku. Často se o náhradě Apache mluví při servírování statického obsahu webu, kde může probíhat několik desítek požadavků s každým načteným HTML dokumentem. To je přesně to místo, kde je Apache na škodu, protože Nginx si vede v podobných situacích mnohem lépe. Subjektivně se dá také říct, že se i lépe konfiguruje.
Webový server Nginx najdete snad ve všech hlavních linuxových distribucích, takže ho stačí nainstalovat z balíčkovacího systému. Kompilace ze zdrojových kódů není nějak zvlášť komplikovaná, ale určitě je pracnější.
Nginx proti Apachi dokáže udržet konstantní čas na odpověď. To samozřejmě nemůže být pravda do nekonečna, ale třeba testy na joeandmotorboat.com ukazují, že Nginx si tento parametr udržel na více požadavcích než Apache.
Nebudeme dále chodit kolem horké kaše, tady je konfigurační soubor nginx.conf, který najdete většinou v adresáři /etc/nginx/.
user www-data www-data;
worker_processes 2;
error_log /var/log/nginx/error.log warn;
pid /var/run/nginx.pid;
events {
worker_connections 1024;
use epoll;
}
http {
include /etc/nginx/mime.types;
default_type application/octet-stream;
# Logování
log_format main '$remote_addr - $remote_user [$time_local] '
'"$request" $status $body_bytes_sent "$http_referer" '
'"$http_user_agent" "$http_x_forwarded_for"';
access_log /var/log/nginx/access.log;
# spool uploads to disk instead of clobbering downstream servers
client_body_temp_path /var/spool/nginx-client-body 1 2;
client_max_body_size 32m;
client_body_buffer_size 128k;
# Nezveřejňovat verzi serveru na chybových stránkách
server_tokens off;
sendfile on;
tcp_nopush on;
tcp_nodelay off;
keepalive_timeout 5;
# Komprese
gzip on;
gzip_http_version 1.0;
gzip_comp_level 2;
gzip_proxied any;
gzip_min_length 1100;
gzip_buffers 16 8k;
gzip_types text/xml text/plain text/css application/x-javascript application/xml application/xml+rss text/javascript;#text/html
# Vypneme kompresi pokud má uživatel IE6
gzip_disable "MSIE [1-6].(?!.*SV1)";
gzip_vary on;
# nastavení proxy
proxy_redirect off;
proxy_set_header Host $host;
# Proměnné v hlavičce, důležité pro logování
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_max_temp_file_size 0;
# Časové limity
proxy_connect_timeout 90;
proxy_send_timeout 90;
proxy_read_timeout 90;
proxy_buffer_size 4k;
proxy_buffers 4 32k;
proxy_busy_buffers_size 64k;
proxy_temp_file_write_size 64k;
include /etc/nginx/sites-enabled/*;
}
Konfigurák je možná trochu delší, ale o to bude jednodušší konfigurace jednotlivých virtual hostů. Názvy konfiguračních voleb jsou naštěstí dostatečně výstižné, ale pokud by náhodou nebyly, pomůže přehledně zpracovaná dokumentace.
Důležité parametry pro běh Nginxu máme a můžeme jít k jednotlivým webům. Konfiguraci pro weby si od hlavního konfiguráku oddělíme a umístíme ji do /etc/nginx/sites-enabled/. Zde se musíme rozhodnout, jestli chceme využít jen proxy na všechno a zabránit tak využívání některých bezpečnostních problémů Apache, mezi které se řadí i slow loris a nebo to uděláme „lépe“ a budeme Nginxem servírovat i statická data.
V prvním případě uložíme do souboru /etc/nginx/sites-enabled/default.conf něco takového.
server {
listen 80 default_server;
# Do server name dáme nějaký nesmysl
server_name _;
# Vypneme logování nebo nastavíme správnou cestu
access_log off;
error_log off;
# Reverzní proxy pro web server běžící na localhostu
location / {
proxy_pass http://127.0.0.1:80/;
}
}
V tomto případě bude Nginx všechny požadavky předávat Apachi, který běží na lokální adrese nepřístupné z venku. Tento kousek konfiguráku bude zpracovávat všechny požadavky a bude předávat i řádek s Host v HTTP hlavičce. Tím pokryje všechny domény. Díky tomu, že jsme na začátku nastavily předávání proměnných X-Real-IP a X-Forwarded-For, budeme moci z Apache dostávat i správné logy, ale o tom níže.
Efektivnější je si dát práci s konfiguračním souborem pro každou doménu a servírovat Nginxem i statický obsah.
server {
listen 80;
server_name example.com;
access_log off;
error_log off;
# Vypneme logování nebo nastavíme správnou cestu
location / {
proxy_pass http://127.0.0.1:80/;
}
location /static {
alias /var/www/static;
}
location /static2 {
alias /var/www/static2;
}
}
Proti předchozímu příkladu přibylo sedm řádek na konci, které se postarají o to, aby požadavek na cokoli ve /static a /static2 neprošel do Apache, ale rovnou vrátil potřebný obsah.
Logování v Apachi
S požadavkem od proxy přijdou v hlavičce také proměnné X-Real-IP a X-Forwarded-For. Po nainstalování modulu mod_rpaf, bude Apache dávat pozor, jestli náhodou není X-Forwarded-For v HTTP hlavičce a pokud ano, řekne Apachi, že jde o tuto adresu a ten ji použije při logování. To samozřejmě nebude efektivní, pokud budeme statické soubory řešit na Nginxu. V takovém případě je možná rozumnější vytvářet logy tam.
Závěr
Nginx je univerzální nástroj, který se umí dobře přizpůsobovat různým situacím. Dobře komunikuje s Pythonem, Ruby, PHP i s jinými webovými servery, jak jste se mohli přesvědčit výše. Zvládá také zabezpečení přes SSL.
Jeho autorem je rus Igor Sysoev a poprvé byl zveřejněn v roce 2004. Momentálně je používán přibližně na 6 % z milionu nejvýznamnějších stránek na světě.