Linux E X P R E S

Facebook

Konfigurace a optimalizace Apache

O nesporných kvalitách HTTP serveru Apache ví téměř každý, kdo se pohybuje v oblasti webhostingu a webových technologií obecně. Přesto tyto kvality často zůstávají zbytečně nevyužity - přestože stačí tak málo. Vhodným nastavením můžeme poměrně snadno získat vyšší výkon, nové funkce nebo lepší využití těch stávajících. Bylo by chybou nesnažit se vytěžit z tohoto vynikajícího serveru maximum.


V následujícím textu budu předpokládat u čtenáře znalosti jak internetových technologií, tak i používání serveru Apache. Nebudu se tedy zmiňovat o tom, jak tento program získat, nainstalovat, spouštět atd. O to více bych se chtěl věnovat těm méně známým aspektům. Uváděná fakta budou odpovídat verzi 2.0.54 provozované na distribuci Fedora Core 4 (32bitová verze). Pro jiné případy budou samozřejmě některé detaily odlišné, což si jistě každý (za pomoci dokumentace) odpovídajícím způsobem upraví.

Základní konfigurace

Konfigurační soubory z distribuce jsou prakticky připraveny k okamžitému použití. Stačí jen pár drobných změn a server lze ihned provozovat. Přesto bych chtěl upozornit na pár maličkostí, kterým se vyplatí věnovat pozornost. Začneme direktivou ServerName - nastavte platnou adresu (a port!), aby správně fungovala přesměrování. Když už jsme u toho, direktiva Listen určuje porty, na kterých Apache naslouchá, a případně i IP adresy (někdy se to může hodit). ServerAdmin je poněkud kontroverzní - měla by zde být totiž fungující (často kontrolovaná) adresa správce serveru. Bohužel se tak tato adresa dostane do spárů spammerů (a v chybových zprávách nelze používat obvyklá ochranná opatření). Pokud má adresa nějakou běžnou podobu (např. webmaster@domena), klidně ji tam dejte - spammeři na ni, podobně jako na jiné generické adresy, budou stejně posílat zprávy.

Dobrým nápadem je zapnutí perzistentního spojení (přenos více objektů v jedné relaci - direktiva KeepAlive). Ve výchozím nastavení je tato volba vypnuta, ale protože pro drtivou většinu browserů nepředstavuje problém, doporučuji zapnout. Související direktivy MaxKeepAliveRequests a KeepAliveTimeout ponechte v původní podobě.

Přizpůsobení k obrazu svému

Kliknout na tlačítko Spustit a o více se nestarat. To určitě není váš případ, protože kdo touží po něčem takovém, nevybere si Apache. Ten totiž vyniká právě širokými možnostmi přizpůsobení konkrétním situacím. Nastavení není vždy úplně nejjednodušší, ale zato se můžeme plně spolehnout, že Apache bude dělat právě to, co si člověk přeje.

Podmíněné sekce

Konfigurační soubory Apache umožňují vázat platnost direktiv na splnění určitých podmínek. Direktivy se umístí do sekce (kontejneru) s určením podmínky.

Onou podmínkou může být třeba přítomnost modulu - sekce pak vypadá: ... . V distribučním konfiguračním souboru je několik takových sekcí, pro bližší poznání tam stačí nahlédnout. Zajímavou možností je závislost na tom, zda je, nebo není definován nějaký vnější parametr. Ten se poskytuje z příkazové řádky. Pak to vypadá třeba takto:

LogFormat "%t %{Referer}i %{User-agent}i" extralog
CustomLog logs/extra_log extralog

Pokud je definován parametr WriteExtraLog, zapne se zvláštní logování s uvedeným formátem. Tato situace nastane, pokud server spustíme s patřičným argumentem: /usr/sbin/httpd -DWriteExtraLog.

Sekce určitě každý zná, používají se pro direktivy ovlivňující konkrétní adresář. Můžeme ale použít také , kde se místo přesného názvu adresáře používá regulární výraz. Podobný význam mají sekce a - vkládají se do nich direktivy pro soubory s určitým názvem, resp. vyhovující zadanému výrazu.

Kontejnery a zase odpovídají logickému umístění definovanému URL (na rozdíl od , kde se pracuje s cestami na disku). Lze to používat např. pro jednoduché řízení přístupu nebo způsobu prezentace.

Uplatňování restrikcí

Pokud necháme uživatelům volné pole působnosti, může se snadno stát, že se server stane obětí DoS útoku nebo bude aspoň zbytečně přetížený. Je proto více než vhodné nastavit určitá omezení, která na jednu stranu neomezí běžné uživatele, ale současně odstaví útočníky nebo ty, kteří by server používali nežádoucím způsobem.

Útok DoS, Denial of Service, je útok na systém nebo síť, který zapříčiní nedostupnost služby pro uživatele. Princip spočívá v přetížení systému či vyčerpání dostupných systémových prostředků. (Volně podle http://en.wikipedia.org/wiki/DOS_attack)

Máme celou skupinu direktiv začínajících slovem Limit. Právě ty použijeme k základnímu vymezení mantinelů. Podívejme se na příklad:

LimitRequestBody 1024576
LimitRequestFields 30
LimitRequestFieldSize 1024
LimitXMLRequestBody 1024576

První direktiva omezuje velikost požadavku na 1 MB. To je ještě poměrně vysoká hodnota, která se využije prakticky jen při uploadu souborů. V ostatních případech je lepší ji ještě snížit, např. na 50 kB. Další dvě direktivy omezují počet polí (hlaviček) a jejich velikost. Běžně by se nemělo výchozí nastavení měnit, ale např. pro jednoúčelové servery to opodstatnění má. A konečně poslední uvedený řádek omezuje velikost XML požadavků - tedy nejčastěji těch souvisejících s technologií WebDAV.

WebDAV je zkratka pro Web-based Distributed Authoring and Versioning, chápe se jako rozšíření http protokolu, které vypracovala stejnojmenná pracovní skupina. Záměrem je vytvořit z webového prostoru (vzdáleného serveru) médium, na něž lze zapisovat a lze z něj číst data. (Volně podle http://en.wikipedia.org/wiki/WebDAV)

Další skupina direktiv začíná na RLimit - a týká se limitu systémových prostředků. Cílem je omezit zejména CGI skripty tak, aby zbytečně nezatěžovaly stroj. Omezit můžeme počet procesů, paměť a spotřebovaný čas procesoru. Pokud tyto hodnoty nenastavíme, použije se nastavení operačního systému.

Vlastní chybové dokumenty

Často se setkáváme s názorem (a do značné míry oprávněným), že jsou chybové zprávy serveru příliš technicky orientovány a že by měl být návštěvník o chybě informován nějakým příjemnějším způsobem. To není problém, nastavení chybových stránek lze změnit, nebo jejich podobu přímo přenechat správci obsahu webu.

Použijeme k tomu direktivu ErrorDocument. Lze uvést odkaz na místní i vzdálený soubor (pro chybu 401 pouze na místní), nebo dokonce i text zprávy (v uvozovkách). Direktivu můžeme vložit mj. i do souboru .htaccess, každému adresáři lze tedy nastavit vlastní chybovou zprávu.

Chyba 401 nemůže mít vzdálený chybový dokument právě proto, že se používá přesměrování. Klient by tak nemohl správně reagovat - vyžádat si od uživatele jméno a heslo a zaslat je na server k autentizačnímu procesu.

Umísťování čehokoliv do souborů .htaccess je sice lákavé, ale pokud máte možnost měnit konfiguraci, je právě její změna skoro vždy bezpečnější a efektivnější volba. Soubory .htaccess je lépe ponechat pouze pro případy, kdy si tak svůj adresář konfiguruje uživatel nemající právo zasahovat do konfigurace.

Pozor však na dvě věci. Jednak na mechanismus zpracování při uvedení vzdáleného souboru - nefunguje to bohužel tak, že by server poslal přímo načtený obsah uvedeného souboru, ale místo toho vrátí kód přesměrování na nový dokument. Z toho mohou plynout různé problémy, hlavně pro vyhledávače, příp. mirrorovací nástroje.

Druhý problém přinášejí některé prohlížeče Microsoftu. Nahrazují totiž chybové zprávy menší než 512 B vlastní zprávou - proto doporučuji, aby v zájmu maximální kompatibility byly chybové zprávy vždy delší.

Uživatelské adresáře

Poslední, na co se v rámci přizpůsobování podíváme, jsou uživatelské adresáře. Je to jednoduchá cesta, jak si mohou uživatelé (mající normální unixová konta) snadno vytvářet své osobní stránky. Takže pokud někdo zadá adresu ve tvaru http://stroj.nejaka.domena/~uzivatel/, server mu poskytne hlavní stránku uživatele (a stejným způsobem i ostatní stránky).

Uživatelské adresáře nastavujeme direktivou UserDir. Nejvíc napoví příklad:

UserDir public_html
UserDir disabled
UserDir disabled root
UserDir http://nejaka.domena/~*/

První příklad je klasické namapování na podadresář public_html v domovském adresáři. Druhý řádek způsobí vypnutí této funkce pro všechny uživatele (některé můžeme explicitně povolit), třetí ji vypne pouze pro uvedeného uživatele (root). Poslední ukazuje, jak použít přesměrování na jinou adresu - hodí se v případech, kdy mají uživatelé uloženy své stránky na jednom centrálním místě, ale na dalších strojích v síti běží Apache (a případné pokusy zobrazit něco odsud jsou přesměrovány na správné místo).

Virtuální servery

Doby, kdy jeden logický server (pro jednu doménovou adresu) běžel na jednom serveru fyzickém, jsou dávno minulostí. V dnešní době je zcela běžné, že na jednom stroji funguje větší množství virtuálních serverů, aniž by na sebe vzájemně měly přímý vliv. Tato problematika je tedy klíčová pro většinu serverů, které mají sloužit pro účely webhostingu.

Cest, kterými se lze při zprovoznění virtuálních serverů vydat, je mnoho a každý má nějakou svoji osvědčenou. Jednu z nich nyní nastíním. Netvrdím, že je nejlepší, ale představuje postup, jak se rychle dobrat k rozumným výsledkům. Ještě dodám, že se samozřejmě jedná o virtuální servery na jediné IP adrese.

Situace se bude mírně lišit pro "plnohodnotné" servery (s možností vlastní konfigurace) a servery poskytované "jako housky na krámě" (unifikované - např. pro freehosting). V obou případech ovšem zajistěte, aby direktiva UseCanonicalName měla hodnotu Off (proto, aby odkazy na sebe sama fungovaly na základě hlavičky Host).

Plnohodnotné virtuální servery

Takové servery mají vlastní konfigurační sekce, kde jim lze nastavovat mnoho specifických parametrů (odlišně od globální konfigurace). Začneme tím, že v adresáři /etc/httpd vytvoříme podadresář nazvaný např. conf.vhosts. Do něho se budou přidávat konfigurační soubory pro jednotlivé servery. Aby je Apache zpracovával, přidáme do hlavního konfiguračního souboru řádek:

Include conf.vhosts/*.dflt
Include conf.vhosts/*.conf

Nejprve vytvoříme výchozí server (použije se, pokud klient nepošle hlavičku Host). Používáme-li totiž virtuální servery, standardní nastavení pro poskytování dokumentů (DocumentRoot atd.) se nepoužije. Protože výchozí server je ten, který je uveden jako první, musíme zajistit, aby to byl ten správný. Lze to udělat různě, mně se osvědčil postup, že tento jediný soubor má příponu .dflt, kdežto všechny ostatní .conf (pořadí direktiv - viz výše - zajistí, že výchozí server bude první). Soubory je nejlépe pojmenovávat podle domén, k nimž přísluší (třeba vychozi.domena.cz.dlft nebo dalsi.domena.org.conf).

Obsah každého ze souborů bude zhruba následující:

ServerName www.nejaka.domena
ServerAlias nejaka.domena web.nejaka.domena
DocumentRoot /www/vhosts/nejaka.domena
ServerAdmin webmaster@nejaka_domena

Myslím, že je vše zcela zřejmé - toto je základní množina direktiv, lze ovšem používat i mnohé jiné. Uvedená konfigurace platí pro případ, že nezáleží na IP adrese, kde server naslouchá. Do hlavního konfiguračního souboru pak uvedeme direktivu:

NameVirtualHost *:80

Pokud bychom chtěli rozlišení podle IP adres nebo portů, pak touto direktivou specifikuje všechny adresy (a/nebo porty), na kterých chceme virtuální servery provozovat (pozor - musíme samozřejmě použít i odpovídající direktivy Listen). Sekce pro jednotlivé servery by pak obsahovaly vždy dané adresy, resp. porty (např. nebo ).

Zvláštní zmínku si zaslouží logování. Samostatný log (se záznamem přístupů) pro virtuální server je zcela samozřejmým požadavkem, proto lze přímo v konfiguraci určit, kam se bude zapisovat. Kromě případů, že provozujeme jen několik málo virtuálních serverů, je to ale špatná cesta. Problémů je hned několik, nejvýznamnější je ale omezení počtu otevřených deskriptorů. Proto vřele doporučuji použít jinou metodu - tvorbu společného logu s přidáním rozlišovací informace a následné rozdělení programem split-logfile, který je s Apache dodáván. Statistické zpracování se stejně dělá dávkově, takže to není problém.

Pro generování logu tedy použijeme tuto direktivu (do hlavní konfigurace):

LogFormat "%v %h %l %u %t \"%r\" %>s %b" vhostformat
CustomLog logs/vhostlog vhostformat

Tím se bude generovat log, který bude v prvním sloupci obsahovat název virtuálního serveru. Vytvořený log bude "potravou" pro program split-logfile. Ten je sice součástí projektu Apache, ale v distribučním balíku serveru chybí. Musí se tedy nainstalovat samostatně. Program přijímá data na standardním vstupu a vytváří samostatné logy. Lze mu tedy přímo posílat společný log rourou, ale lepší je provádět dělení dávkově (nejlépe těsně před statistickým zpracováním jednotlivých logů).

Jednoduché virtuální servery

Pro systémy hostující stovky až tisíce virtuálních serverů (s jednotnými parametry) je to zbytečně složité řešení. Můžeme to udělat jednodušeji, kdy pro přidávání dalších serverů nebude potřeba vytvářet konfigurační soubory a při změně (přidání, odebrání) vždy znovu nechávat parsovat. Manipuluje se pak pouze s adresáři a do konfigurace není nutné nijak zasahovat.

Stačí pouze jediné pravidlo (resp. ještě další v případě, že bychom potřebovali používat CGI). Může vypadat třeba takto:

VirtualDocumentRoot /var/www/vhosts/%-2.0.%-1.0/

Uvedený příklad předpokládá, že v adresáři /var/www/vhosts budeme vytvářet adresáře jednotlivých serverů, a to ve tvaru adresy domény 2. úrovně - i požadavky obsahující případné domény dalších úrovní (třeba www) budou vždy směrovány sem. Pokud by mělo být chování jiné, formát se upraví odpovídajícím způsobem (použití je popsáno v dokumentaci). Ještě se k tomu vrátíme při optimalizaci výkonu.

S logováním to bude podobné jako v předchozím případě. Rozdíl bude ve formátu, namísto malého "v" použijeme velké:

LogFormat "%V %h %l %u %t \"%r\" %>s %b" vhostformat

Pokud potřebujeme používat CGI (což ovšem bývá u serverů tohoto druhu velice neobvyklé), lze použít společný adresář pro skripty (nastavíme pomocí direktivy ScriptAlias), anebo pro každý server samostatný (direktiva VirtualScriptAlias).

Zajímavé moduly

Apache je modulární server. Většinu modulů vnímáme jako zcela samozřejmou součást jeho schopností, o některých se naopak ví velice málo. Ať tak či tak, hlavně některé z těchto modulů stojí za to, aby jim byl věnován zvláštní prostor.

Rewrite

Modul (mod_rewrite) slouží k "přepisu" URL objektu - původní lokátor z požadavku klienta nahradí (na základě pravidel) nějakým jiným. Možností použití je řada, nejčastěji asi (v rámci SEO) pro vytváření URL vhodných pro indexaci ve vyhledávačích. Jedná se o nesmírně silný nástroj, jehož dobré zvládnutí ovšem není triviální. Lze ho ovládat jak přes konfigurační soubory, tak lokálně pomocí souborů typu .htaccess.

Než se pustíme do samotného používání modulu, chtěl bych upozornit na jednu důležitou věc. Přepis na úrovni serveru (tedy definovaný v konfiguraci) je rychlý a jednoduchý. Naopak přepis v adresáři (soubor .htaccess) zpomaluje zpracování, protože může odkazovat do úplně jiného místa na serveru a musí tedy dojít k opětovnému vyhodnocení URL serverem. Na druhou stranu, změny v konfiguraci vyžadují její opětovné načtení při každé změně (a samozřejmě i právo změnu provést) - kdežto pro druhý způsob stačí mít právo zápisu do adresáře se souborem .htaccess. Abychom mohli přepis vůbec používat, musíme mechanismus nejdřív zapnout (ve výchozím stavu je vypnutý):

RewriteEngine On.

Základem použití přepisu je direktiva RewriteRule. Obsahuje regulární výraz (v perlovském formátu), podle něhož se hledá vzorek řetězce v URL, a dále formátovací řetězec, jímž se tento vzorek nahradí. Direktivy se zpracovávají v pořadí, v jakém jsou uvedeny - na to je potřeba dát pozor, protože se projeví již provedené přepisy podle předchozích pravidel. Formátovací řetězec může obsahovat jak pevný text, tak samozřejmě odkazy na nalezené vzorky řetězce, na podmínku splněnou v direktivě RewriteCond (viz dále) a také hodnoty proměnných prostředí nebo mapovacích funkcí. Direktiva může mít ještě třetí parametr - příznaky. Jejich pomocí můžeme ovlivňovat způsob zpracování pravidel, vracet klientům různé HTTP stavové kódy apod.

Direktiva RewriteCond slouží k testování různých podmínek, které nemusejí vycházet přímo z daného URL. Lze pracovat třeba s proměnnými prostředí nebo údaji z HTTP hlaviček. Sada direktiv RewriteCond se vždy vztahuje k nejblíže následující direktivě RewriteRule.

Podívejme se na dva příklady použití. Nejprve velmi jednoduchý - chceme zajistit, aby se k RSS obsahu přistupovalo přes soubor rss.xml (s některými prohlížeči je problém, pokud má soubor jinou příponu, bez ohledu na MIME typ), ale obsah byl generován PHP skriptem. Lze to udělat takto (soubor je v kořenovém adresáři):

RewriteRule ^rss\.xml$ %{DOCUMENT_ROOT}/rss.php

Uvedený tvar platí pro soubor .htaccess, v konfiguraci by se musel mírně modifikovat regulární výraz. Přejděme ale k SEO - stránky s "hezkými" URL půjdou snáze nalézt, proto provedeme takový přepis, abychom je mohli používat. Zde je příklad (vše patří na jeden řádek):

RewriteRule ^([^/]+)/?([^/]+)?/?([^/]+)/?$ %{DOCUMENT_ROOT}/index.php?prvni=$1&druhy=$2&treti=$3 [QSA]

Kdo zná perlovské regulární výrazy, jistě hned vidí, jak zde přepis pracuje. V URL je cesta s jedním až třemi adresářovými úrovněmi, které se přepíší na hodnoty příslušných proměnných (adresářové cesty nemusejí být ukončeny lomítkem). Příznak QSA říká, že případná dotazová část URL se má přidat na konec.

WebDAV

Tato technologie publikování se používá pro čím dál víc účelů, je proto dobře, že ji Apache odpovídajícím způsobem podporuje. Na samotné aktivaci a nastavení není nic složitého.

DAV by se měl povolovat (direktivou DAV On apod.) pouze pro co nejmenší, zcela izolované oblasti, kam by se již nemělo přistupovat jinými způsoby. Škálu povolených operací lze omezit použitím kontejnerů nebo , hodí se také omezení velikosti požadavku (direktiva LimitXMLRequestBody) kvůli případným DoS útokům. Modul pro WebDAV pracuje s právy uživatele a skupiny podle nastavení v konfiguračním souboru Apache. Co se týká povolování přístupu, vřele se doporučuje používat metodu HTTP Digest (podle RFC 2617), a když už se použije základní metoda, pak jedině přes SSL.

User tracking

Často se hodí mít možnost sledovat pohyb uživatele po serveru. Termín cookies snad každý bude znát - právě s jejich pomocí tento modul zaznamenává, kudy uživatel prochází. Nezbytnou podmínkou samozřejmě je, aby měl v prohlížeči práci s cookies povolenu.

Mechanismus se zapíná direktivou CookieTracking On (na kterékoli úrovni, od globální až po soubor .htaccess). Současně s tím je potřebné napravit nesmyslný relikt, který v nastavení přetrvává - a sice používání původního (nejstaršího, vzniklého s prohlížečem Netscape) formátu cookies. Nastavte proto, nejlépe na globální úrovni, ten nejnovější, definovaný v RFC 2965. Docílí se tak direktivou CookieStyle Cookie2.

Dále nastavíme také doménu a název cookie (budou součástí identifikátoru - důležité hlavně u virtuálních serverů!). Vypadá to zhruba následovně:

CookieDomain .nejaka.domena.org
CookieName mujserver

Všimněte si, že specifikace domény začíná tečkou - její použití je povinné. Pokud neurčíme jinak, platnost cookie vyprší s uzavřením browseru (s koncem session). Lze ale platnost určit časově (např. jednu hodinu), a to direktivou CookieExpires.

Sledování by nebylo k ničemu, kdybychom ho nikam nezaznamenávali. Proto do formátu samostatného nebo společného (podle toho, jak se to pak bude zpracovávat - doporučuji ale obecně spíš společný) logu přidáme sloupec vypadající takto: %{cookie}n. V tomto sloupci bude identifikátor cookies, podle kterého lze pak záznamy filtrovat, seskupovat apod.

Diskuze (0) Nahoru