Selfhostet Analytics

Eine selbst gehostete Alternative zu Google-Analytics

Selfhostet Analytics

Nicht jeder möchte gleich mit einem kompletten SIEM seine Webseiten überwachen. Es geht auch einfacher.

Google Analytics

Die wahrscheinlich einfachste Lösung dürfte wohl Google Analytics sein. Man fügt einfach eine weitere Property hinzu, für die man dann einen Code-Schnipsel erhält. Diesen Schnipsel fügt man auf seiner Webseite ein, und schon bekommt Google alle Informationen geliefert, wer die Webseite aufruft:

Der Vorteil: Weil Google weiß, ob der Webseitenbesucher männlich oder weiblich ist, oder wie alt er ist und wo er wohnt, bekommt man in der Analyse sehr genaue Informationen über die Zielgruppe seines Internetauftrittes.
Der Nachteil: Und wieder hat man dem Datenkraken Google weitere Informationen zur Verfügung gestellt. Was der Konzern letztlich damit macht, bleibt der Fantasie überlassen.

Selfhosted

Wer mich kennt, weiß dass ich meine Dienste lieber selbst betreibe. Doch nicht jeder möchte gleich ein ganzes SIEM in Betrieb nehmen, nur um zu sehen, wer auf der Webseite unterwegs ist.

Eigener Webserver mit offiziellen Zertifikaten
Der Basis-Artikel für alle folgenden Services, die ich hier demonstrieren werde…

Ich betreibe meine Webservices überwiegend hinter einem Reverse-Proxy. Dazu setze ich den Nginx-Proxy-Manager ein. Da dieser die Requests an den gerufenen Dienst weiterleitet, sieht er den Datenverkehr zwischen dem Browser und dem gerufenen Service (z.B. die Webseite).

Wenn ich also wissen will, wer auf meinen Webseiten unterwegs ist: Der Proxy weiß es!

Ein schönes Dashboard

Um nun die zentralen Logs des Proxies auszuwerten, habe ich mich für goaccess entschieden. Und da ich meine Dienste normalerweise in Containern organisiere, ist auch dieses Modul wieder sehr leicht hinter dem Nginx-Proxy-Manager hinzuzufügen:

services:
###############################################
####        nginx-proxy-manager           #####
###############################################
  nginx-proxy-manager:
    image: 'jc21/nginx-proxy-manager:latest'
    container_name: "nginx-proxy-manager"
    restart: unless-stopped
    ports:
      # These ports are in format <host-port>:<container-port>
      - '80:80' # Public HTTP Port
      - '443:443' # Public HTTPS Port
      - '127.0.0.1:81:81' # Admin Web Port only per ssh-tunnel
      # Add any other Stream port you want to expose
      # - '21:21' # FTP
    environment:
      # Uncomment this if you want to change the location of
      # the SQLite DB file within the container
      # DB_SQLITE_FILE: "/data/database.sqlite"
      # Uncomment this if IPv6 is not enabled on your host
      DISABLE_IPV6: 'true'
    labels:
      - "com.centurylinklabs.watchtower.enable=true"
    volumes:
      - ./nginx-proxy-manager/data:/data
      - ./nginx-proxy-manager/letsencrypt:/etc/letsencrypt
    networks:
      - web

  goaccess:
    image: 'xavierh/goaccess-for-nginxproxymanager:latest'
    container_name: goaccess
    restart: always
    expose:
      - '7880'
    environment:
      - TZ=Europe/Berlin         
      - SKIP_ARCHIVED_LOGS=true #optional
      - DEBUG=False #optional
      - BASIC_AUTH=False #optional
      - BASIC_AUTH_USERNAME=user #optional
      - BASIC_AUTH_PASSWORD=pass #optional   
      - EXCLUDE_IPS=127.0.0.1 #optional - comma delimited 
      - LOG_TYPE=NPM #optional - more information below
      - ENABLE_BROWSERS_LIST=True #optional - more information below
      - CUSTOM_BROWSERS=Kuma:Uptime,TestBrowser:Crawler #optional - comma delimited, more information below
      - HTML_REFRESH=5 #optional - Refresh the HTML report every X seconds. https://goaccess.io/man
      - KEEP_LAST=30 #optional - Keep the last specified number of days in storage. https://goaccess.io/man
      - PROCESSING_THREADS=1 #optional - This parameter sets the number of concurrent processing threads in the program's execution, affecting log data analysis, typically adjusted based on CPU cores. Default is 1. https://goaccess.io/man
    labels:
        - "com.centurylinklabs.watchtower.enable=true"
    volumes:
        - ./nginx-proxy-manager/data/logs:/opt/log
        - ./goaccess/custom:/opt/custom #optional, required if using log_type = CUSTOM

  networks:
    web:
      external: true
    backend:
      external: true

Diesen Text kann man direkt unter seinem Abschnitt des nginx-proxy-managers hinzufügen. Dabei ist nur eines zu beachten: Da goaccess auf die Logs des Proxies zugreifen können muss, müssen diese in den Ordner /opt/log gehängt werden. Ich habe dies in der vorletzten Zeile gemacht, mittels ./nginx-proxy-manager/data/logs:/opt/log. Hier muss man natürlich den Ort seiner eigenen Logs angeben.

Gestartet wird der Container wie üblich via

docker-compose up -d goaccess && docker-compose logs -f goaccess

Dann kann man auch diesen Dienst gleich im nginx-proxy-manager einbinden. Läuft der Server im lokalen Netz, kann man direkt auf den npm per http://serverip:81 zugreifen. Läuft der npm auf einem Remote-Server, muss man sich vorher per ssh -D 65535 user@remote-server einloggen und kann dann seinen Browser mit dem Befehl chromium --proxy-server="socks5://localhost:65535" http://checkip.dyndns.org starten. Nach diesem Zwischenschritt erreicht man den npm wie gewohnt unter http://localhost:81 :

Das Ergebnis

Ruft man nun die zugewiesene URL auf, öffnet sich das Dashboard von goaccess:

Welche Informationen interessant sind, kann man ein- bzw. ausblenden lassen:

Man kann auch gut sehen, woher die Aufrufe meiner Seiten kommen. Da ich auch die Seitenaufrufe per IP logge, sehe ich in dieser Ansicht zusätzlich auch, woher Schwachstellen-Scans kommen:

Es gibt natürlich noch mehr Diagramme und Tabellen, wie man sie auch bei goaccess nachschauen kann.

Fazit

Mit relativ wenig Aufwand ist es möglich zu analysieren, wer auf die eigenen Webservices zugreift. Und das völlig ohne Informationen an Google zu liefern.

Für mich ist es immer ein Erfolg, wenn ich Bekannten einen einfachen Weg aufzeigen kann, der dabei einen großen Informationsgewinn bringt. Denn es war doch eine Kleinigkeit, den Code-Schnipsel der docker-compose.yml-Datei hinzuzufügen...