Návštěvnost svých pěti webů sleduji bez Google Analytics, bez cookies a bez externí služby. Statistiky počítá GoAccess přímo z logů Apache na mém domácím serveru, každou hodinu je aktualizuje a zobrazuje jen v domácí síti. Aby čísla dávala smysl, musel jsem nejdřív naučit Apache vidět skutečné adresy návštěvníků za Cloudflare.
Proč ne Google Analytics
Weby běží na vlastním serveru s Proxmoxem (viz Migrace pěti webů z VPS na vlastní server) a chtěl jsem, aby i statistiky zůstaly u mě. Zvažoval jsem dvě cesty:
| Rozbor logů (GoAccess) | Měřicí skript (Matomo) | |
|---|---|---|
| Zásah do webů | žádný | skript nebo modul v každém webu |
| Cookies a souhlas | nic se do prohlížeče neukládá | lze nastavit bez cookies |
| Provoz | jeden balíček, pár MB | vlastní kontejner s PHP a databází, dostupný z internetu |
| Detail | návštěvy, stránky, zdroje, prohlížeče, chyby 404 | navíc čas na stránce, cesta návštěvníka, cíle |
Pro osobní web a pár firemních prezentací stačí rozbor logů. Matomo si nechávám jako možné rozšíření.

Past: v logu jsou jen adresy Cloudflare
Domácí připojení je za CGNAT, takže weby jsou dostupné přes Cloudflare proxy a IPv6 (Domácí server za CGNAT). Každé spojení na server proto přichází z adresy Cloudflare. Statistika by ukazovala několik „návštěvníků“ s obrovským počtem přístupů.
Cloudflare posílá skutečnou adresu v hlavičce CF-Connecting-IP. Apache ji umí převzít modulem mod_remoteip, ale jen od důvěryhodných adres, aby hlavičku nemohl podvrhnout kdokoli jiný. Server je za Cloudflare dostupný jen přes IPv6, proto stačí IPv6 rozsahy Cloudflare (aktuální seznam je na cloudflare.com/ips):
# /etc/apache2/conf-available/cloudflare-remoteip.conf
RemoteIPHeader CF-Connecting-IP
RemoteIPTrustedProxy 2400:cb00::/32
RemoteIPTrustedProxy 2606:4700::/32
RemoteIPTrustedProxy 2803:f800::/32
RemoteIPTrustedProxy 2405:b500::/32
RemoteIPTrustedProxy 2405:8100::/32
RemoteIPTrustedProxy 2a06:98c0::/29
RemoteIPTrustedProxy 2c0f:f248::/32
# Log s adresou klienta (%a) misto adresy spojeni (%h)
LogFormat "%a %l %u %t \"%r\" %>s %O \"%{Referer}i\" \"%{User-Agent}i\"" combinedPoslední řádek je podstatný a často se na něj zapomíná. Standardní formát combined v Debianu zapisuje %h, tedy adresu spojení, a ta zůstane adresou Cloudflare i se zapnutým modulem. Adresu převzatou z hlavičky obsahuje %a. Předefinování formátu v samostatném souboru platí pro všechny weby najednou, protože se načítá po hlavní konfiguraci.
a2enmod remoteip
a2enconf cloudflare-remoteip
apache2ctl configtest
systemctl reload apache2Ověřil jsem to návštěvou z mobilu přes mobilní data. V logu se místo adresy Cloudflare objevila adresa operátora. Vedlejší výhoda: fail2ban na serveru teď vidí skutečné adresy a nehrozí, že by omylem zablokoval Cloudflare a s ním všechny návštěvníky.
GoAccess: přehled pro každý web zvlášť
GoAccess je v repozitáři Debianu 13 (verze 1.9.3). Každý web má vlastní log, takže skript vytvoří samostatný přehled pro každou doménu a rozcestník:
apt install -y goaccess#!/bin/bash
# /usr/local/bin/goaccess-report.sh
OUT=/var/www/goaccess
DB=/var/lib/goaccess
L=/var/log/apache2
OPTS="--log-format=COMBINED --persist --anonymize-ip --ignore-crawlers --exclude-ip=2001:db8:1:2::-2001:db8:1:2:ffff:ffff:ffff:ffff"
mkdir -p "$OUT"
for SITE in lubomir-bena.cz lubomirbena.cz DALSI_DOMENY; do
mkdir -p "$DB/$SITE"
if [ "$1" = "prvni" ]; then
zcat -f $(ls -1r $L/$SITE-access.log.*.gz 2>/dev/null) $L/$SITE-access.log.1 $L/$SITE-access.log \
| goaccess - $OPTS --db-path="$DB/$SITE" --html-report-title="$SITE" -o "$OUT/$SITE.html" >/dev/null 2>&1
else
goaccess $L/$SITE-access.log.1 $L/$SITE-access.log $OPTS --restore --db-path="$DB/$SITE" \
--html-report-title="$SITE" -o "$OUT/$SITE.html" >/dev/null 2>&1
fi
doneNa konci skript ještě vypíše jednoduchý index.html s odkazy na jednotlivé přehledy. Důležité volby:
--persista--restore: GoAccess si zpracovaná data ukládá a při dalším běhu přidá jen nové řádky. Apache rotuje logy denně a drží jich jen 7, statistika ale díky tomu sahá dál do minulosti.- čtení
.log.1i.log: kolem půlnoci se log rotuje. Bez předchozího souboru by se ztratily poslední minuty dne. Řádky, které už GoAccess zpracoval, přeskočí. --anonymize-ip: v přehledech nejsou celé adresy návštěvníků.--ignore-crawlers: roboti vyhledávačů a AI se nezapočítají.--exclude-ips rozsahem domácí sítě: moje vlastní návštěvy webů jdou také přes Cloudflare a bez vyřazení by se počítaly.
Parametr prvni jsem spustil jednou. Načetl historii ze všech uchovaných logů, starší soubory postupně od nejstaršího. Data před zapnutím mod_remoteip obsahují místo návštěvníků adresy Cloudflare, takže počty unikátních návštěvníků za tyto dny jsou nepřesné.
Aktualizaci každou hodinu zajišťuje cron:
echo "5 * * * * root /usr/local/bin/goaccess-report.sh" > /etc/cron.d/goaccessZobrazení jen v domácí síti
Statistiky nechci mít na internetu. Přehledy proto obsluhuje samostatný virtuální host Apache na portu 8080, který poslouchá jen na domácí IPv4 adrese serveru a pouští jen adresy z domácí sítě:
Listen 192.0.2.10:8080
<VirtualHost 192.0.2.10:8080>
DocumentRoot /var/www/goaccess
<Directory /var/www/goaccess>
Options -Indexes
Require ip 192.0.2.0/24
</Directory>
CustomLog /dev/null combined
</VirtualHost>Zvenku se k přehledům nikdo nedostane: IPv4 je za CGNAT a firewall MikroTiku pouští na server jen porty 80 a 443 z Cloudflare přes IPv6. CustomLog /dev/null zajistí, že se prohlížení statistik nepočítá do statistik. Přehled od GoAccess je jeden HTML soubor s grafy a nenačítá nic z internetu.
Co v přehledech vidím
Pro každý web vidím unikátní návštěvníky a přístupy po dnech, nejčtenější stránky, odkazující weby, operační systémy a prohlížeče a chyby 404. Hned první den ukázal i to, co z Google Analytics nevyčtu: desítky pokusů o /.env, /.git/config nebo /wp-login.php. Jsou to automatické skenery, které hledají zranitelnosti cizích aplikací. Drupal tyto soubory nemá, takže jsou neškodné. Část skenerů se ale tváří jako běžný prohlížeč, a proto je skutečný počet lidí o něco nižší, než ukazuje řádek „Unique Visitors“.
Vyhledávací dotazy, přes které lidé na web přišli, v logu nejsou. Ty doplňuje Google Search Console, se kterou statistiky z logů dobře doplňují.
Shrnutí
- Za Cloudflare je potřeba
mod_remoteips důvěryhodnými rozsahy a log s%amísto%h. - GoAccess z logů Apache nepotřebuje žádný skript ve webu ani cookies.
--persista--restoredrží historii déle, než se uchovávají logy.- Vlastní návštěvy a roboty je dobré vyřadit, skenery zranitelností zůstanou částečně započítané.
- Přehledy jsou dostupné jen z domácí sítě a aktualizují se každou hodinu.
Článek navazuje na sérii Migrace pěti webů z VPS na vlastní server a na článek Webový server v Proxmox LXC.