Apache2: Jak odchudzić nieco plik access.log
Spis treści
Mając serwer www oparty o oprogramowanie Apache2, w pewnym momencie zacznie nas nieco przytłaczać
kwestia logowania do pliku /var/log/apache2/access.log wszystkiego co się nawinie. Jak nazwa pliku
sugeruje, znajdują się w nim komunikaty, które serwer generuje ilekroć tylko ktoś odwiedzi nasz
serwis. Każdy zasób przesłany do klienta, np. style CSS czy obrazki, zostanie zalogowany w powyższym
pliku. Generalnie rzecz ujmując, nie musimy logować wszystkich tych informacji, chyba, że ich
faktycznie potrzebujemy. Trzeba jednak wziąć pod uwagę fakt, że w przypadku obciążonych serwerów,
ilość operacji I/O dysku może być znaczna. Dodatkowo, miejsce na dysku za sprawą takiego obszernego
logu może bardzo szybko się wyczerpać. W tym artykule postaramy się nieco ograniczyć apetyt serwera
Apache2 na logi i oduczymy go logować większość zbędnych komunikatów za sprawą dyrektywy
SetEnvIf/SetEnvIFNoCase .
Całkowite wyłączenie logowania w pliku access.log
Na necie można natknąć się na całą masę postów, których autorzy sugerują całkowite wyłączenie
logowania wszystkich komunikatów trafiających do pliku /var/log/apache2/access.log . Moim zdaniem,
nie jest to zbyt rozważna decyzja. A to z tego względu, że pozbawiamy się informacji o próbie
uzyskania dostępu do zasobów zastrzeżonych. Każdy serwis www ma pewne miejsca, do których nie
wszyscy powinni mieć dostęp. Gdy takie osoby czy boty próbują się w ten obszar zapuścić, zwykle
zwiastuje to początek ataku na serwer. To, czy on się powiedzie zależy od całej masy czynników.
Niemniej jednak, jeśli przeglądamy jakiś log, to zawsze jesteśmy w stanie coś zauważyć. Dlatego też
lepiej nie wstawiać znaku # na początku tej poniższej linijki:
CustomLog ${APACHE_LOG_DIR}/access.log combined
Zamiast tego rozwiązania, dużo lepszym sposobem jest ogarnięcie modułu mod_log_config i wykorzystanie drzemiącego w nim potencjału.
Moduł mod_log_config w Apache2
Moduł mod_log_config jest standardowo włączony w konfiguracji i wykorzystywany praktycznie przez
każdy serwer Apache2. Jedyne co musimy zrobić, to wskazać mu, które wiadomości życzymy sobie
zalogować, w jakiej formie i do jakich plików takie komunikaty mają zostać przesłane. Do wszystkich
tych celów możemy skorzystać z dwóch dyrektyw LogFormat oraz CustomLog .
Dyrektywa CustomLog
Dyrektywa CustomLog służy do logowania zapytań klientów odwiedzających nasz serwer www. Przyjmuje
ona dwa lub trzy argumenty. Dwa są wymagane, a jeden opcjonalny. Dla przykładu, weźmy sobie
standardowy wpis, który figuruje w konfiguracji Apache2 (dwa argumenty):
CustomLog ${APACHE_LOG_DIR}/access.log combined
Ta powyższa linijka rozpoczyna się od nazwy dyrektywy. Następnie mamy pierwszy argument, tj. ścieżkę
do pliku, w której skład wchodzi zmienna ${APACHE_LOG_DIR} oraz nazwa samego pliku access.log .
Obie te rzeczy możemy sobie dostosować. Nie musimy też korzystać ze zmiennej. Jeśli natomiast przy
jej pomocy chcielibyśmy zmienić domyślny katalog logów ( /var/log/apache2/ ) to wystarczy
przypisać tej zmiennej inną ścieżkę w pliku /etc/apache2/envvars . Drugi argument zaś odpowiada
za format logowanych wiadomości. W tym przypadku combined odnosi się to aliasu, który figuruje w
pliku /etc/apache2/apache.conf :
LogFormat "%h %l %u %t \"%r\" %>s %O \"%{Referer}i\" \"%{User-Agent}i\"" combined
O tym trzecim opcjonalnym argumencie powiemy sobie za chwilę. Na razie spróbujmy wyjaśnić sobie
zapis dyrektywy LogFormat .
Dyrektywa LogFormat
Dyrektywa LogFormat odpowiada za format logu trafiającego do pliku, który został określony w
dyrektywie CustomLog . Widzimy wyżej, że domyślna dyrektywa LogFormat ma dwa argumenty, choć ten
pierwszy jest dość długi. Mamy w nim ciąg "%h %l %u %t \"%r\" %>s %O \"%{Referer}i\" \"%{User-Agent}i\"" , który po przetłumaczeniu na ludzki język formatuje komunikat do poniższej
postaci:
%h-- zdalna nazwa hosta lub adres IP, w zależności czy opcjaHostnameLookupsjest włączona w/etc/apache2/apache2.conf.%l-- zdalna nazwa logowania (za sprawą modułumod_ident).%u-- nazwa użytkownika, w przypadku autoryzacji dostępu do zasobów.%t-- czas zalogowania zapytania.%r-- pierwsza linia zapytania.%s-- status lokalnie przekierowanego zapytania.%sodpowiada za oryginalne zapytanie, zaś%>sza końcowe.%O-- wysłane bajty wraz z nagłówkami (wymaga modułumod_logio).%{Referer}i-- odnośnik, z którego klient został przekierowany do danego zasobu serwera.%{User-Agent}i-- identyfikator agenta klienta.
Kompletna lista wszystkich możliwych do wykorzystania opcji jest dostępna w dokumentacji
Apache2. Poniżej zaś jest
przykładowy komunikat, który został zalogowany w pliku access.log :
crawl-66-249-66-157.googlebot.com - - [03/Aug/2016:16:51:12 +0200] "GET /tag/dnsmasq/ HTTP/1.1" 200 13847 "-" "Mozilla/5.0 (compatible; Googlebot/2.1; +http://www.google.com/bot.html)"
Jak widzimy powyżej, format logu możemy sobie dostosować wedle uznania. Znak - oznacza brak
informacji.
Jest też możliwe logowanie warunkowe, tj. takie, gdzie w przypadku wystąpienia jakiegoś zdarzenia, serwer Apache2 zaloguje dodatkowo, np. referer, lub też go pominie. Poniżej krótki przykład:
%!200,304,302{Referer}i
Tak jak wcześniej wykorzystujemy %{Referer}i ale po znaku % dodajemy warunek. Liczby
wykorzystane powyżej odpowiadają za kod błędu protokołu
HTTP: OK, NOT MODIFIED, FOUND. Dodatkowo został
użyty ! , który oznacza negację. Zatem referer nie zostanie zalogowany w tych trzech powyższych
przypadkach.
Moduł mod_setenvif i zaawansowane logowanie warunkowe
Opcjonalnym trzecim argumentem dyrektywy CustomLog jest warunek. Opiera się on o zmienne
środowiskowe, które mogą zostać ustawione za sprawą modułów mod_setenvif i/lub mod_rewrite .
Nam wystarczy jedynie moduł
mod_setenvif. By z niego skorzystać
trzeba go pierw włączyć w konfiguracji Apache2:
# a2enmod setenvif
# systemctl restart apache2
Teraz w konfiguracji wirtualnego hosta możemy określić dyrektywę SetEnvIf/SetEnvIFNoCase i podać
jej wzór dopasowania, przykładowo:
SetEnvIf Request_URI "^\/wp-content\/uploads\/[0-9]*\/[0-9]*\/[\.\-0-9a-zA-Z]*\.(png)|(jpg)|(gif)|(jpeg)$" dontlog
W tym przypadku dopasowujemy żądany przez klienta zasób, a właściwie ścieżkę do niego, w oparciu o
wyrażenia regularne. Generalnie, to pliki *.png , *.jpg , *.jpeg oraz
*.gif w katalogu galerii WordPress'a, zostaną oznaczone tagiem dontlog . Ta nazwa może być
dowolna ale to ją trzeba będzie uwzględnić w dyrektywie CustomLog . Zakładając, że nie chcemy
logować odwołań do tych wszystkich obrazków, możemy w konfiguracji wirtualnego hosta zmienić
standardową dyrektywę CustomLog na tę poniższą:
# CustomLog ${APACHE_LOG_DIR}/access.log combined
CustomLog ${APACHE_LOG_DIR}/access.log combined env=!dontlog
Został dodany trzeci argument w postaci env=!dontlog . Znak !, to negacja, zatem jeśli serwer
Apache2 zobaczy komunikat, który nie ma ustawionego taga dontlog , to ma go zalogować do pliku
access.log . Automatycznie wszystkie komunikaty oznaczone tagiem dontlog nie zostaną zalogowane
w tym pliku, a że nie podaliśmy żadnego innego, to zwyczajnie w ogóle nie zostaną zalogowane i o to
nam chodzi.
My skorzystaliśmy jedynie z ustawienia prostego taga w komunikatach za sprawą Request_URI .
Niemniej jednak, dyrektywa SetEnvIf/SetEnvIFNoCase ma szereg innych aspektów
dopasowań, które możemy
wykorzystać: Remote_Host , Remote_Addr , Server_Addr , Request_Method oraz
Request_Protocol . Dopasowania możemy także robić w oparciu o pola w nagłówku
HTTP. Poniżej kilka
przykładów:
SetEnvIf User-Agent "Robot$" dontlog
SetEnvIfNoCase Referer "^jakas.domena.com/link$ dontlog
SetEnvIf Host "192.168.1.20" dontlog