HitKeep: datenschutzfreundliche Web-Analytics selbst hosten
HitKeep mit Docker und Traefik aufsetzen: cookielose, DSGVO-freundliche Website-Statistik auf dem eigenen Server – mit Tracking-Code und Backups.
Inhaltsverzeichnis
Google Analytics kennt jeder – und genau das ist das Problem: Es schickt die Daten deiner Besucher zu Google, verlangt einen Cookie-Banner und macht dich erklärungspflichtig. HitKeep dreht das um: cookielose Web-Analytics auf deinem Server, unter deiner Domain, ohne dass je ein Byte an Dritte geht.
Was bauen wir?
Am Ende läuft HitKeep 2.13.18 als einzelner Container hinter deinem Traefik, erreichbar
unter https://DEINE_DOMAIN. Du bekommst ein Dashboard mit Seitenaufrufen, Besuchern,
Verweildauer, Referrern und Geräten – gespeist von einem winzigen JavaScript-Snippet, das du
in deine Website einbaust. HitKeep arbeitet cookielos (kein Consent-Banner nötig) und
speichert alles lokal in einer eingebetteten DuckDB-Datenbank. Das Image ist ein
Distroless-Image (rund 68 MB Download, entpackt gut 230 MB auf der Platte), das komplett ohne
externe Datenbank auskommt – ideal für einen kleinen VPS.
Hinweis
Voraussetzungen
- Ein Server mit Debian 13 und laufendem Docker (getestet auf einem netcup VPS).
- Ein Reverse Proxy mit Traefik, der TLS-Zertifikate
per Let’s Encrypt holt. HitKeep bringt keinen eigenen HTTPS-Server mit – Traefik übernimmt
die Verschlüsselung. Dieses Tutorial setzt das dort beschriebene
proxy-Netz und den Resolverlevoraus. - Eine (Sub-)Domain, die auf deinen Server zeigt (A-/AAAA-Record). Wir nutzen im Beispiel
DEINE_DOMAIN. - Die Website, die du messen willst – HitKeep misst jede Seite, in die du das Snippet einbaust.
VPS 1000 G12.5
4 vCore · 8 GB RAM · 128 GB SSD
ab 14,50 €/Monat
Ein einzelner Container mit eingebetteter DuckDB – der kleinste vServer reicht dafür locker.
💶 1 Monat gratis:
Einmal einlösbar, gilt für VPS 1000 G12.5. Im leeren Warenkorb einlösen – der Code legt den Server selbst hinein. Im Warenkorb einlösen →
💶 5 € Gutschein für netcup-Neukunden: immer gültig · nicht für Domains und VPS Lite
Schritt für Schritt
Schritt 1: JWT-Secret erzeugen
HitKeep signiert die Login-Sitzungen mit einem geheimen Schlüssel. Erzeuge dir einen zufälligen 32-Byte-Wert – nicht ausdenken, sondern generieren:
openssl rand -hex 32Du bekommst eine 64 Zeichen lange Hex-Zeichenkette. Kopiere sie – sie kommt gleich in die Konfiguration. Ändert sich dieses Secret später, werden alle offenen Logins ungültig; halte es also stabil und geheim.
Schritt 2: Compose-Datei anlegen
Lege einen Ordner für den Stack an und wechsle hinein:
mkdir -p /opt/hitkeep && cd /opt/hitkeepErstelle die Datei compose.yaml. Ersetze DEINE_DOMAIN durch deine echte Domain und
DEIN_JWT_SECRET durch den Wert aus Schritt 1:
services:
hitkeep:
image: pascalebeier/hitkeep:2.13.18
container_name: hitkeep
restart: unless-stopped
environment:
HITKEEP_PUBLIC_URL: https://DEINE_DOMAIN
HITKEEP_JWT_SECRET: DEIN_JWT_SECRET
HITKEEP_TRUSTED_PROXIES: 172.16.0.0/12
HITKEEP_DB_PATH: /var/lib/hitkeep/data/hitkeep.db
HITKEEP_DATA_PATH: /var/lib/hitkeep/data
HITKEEP_ARCHIVE_PATH: /var/lib/hitkeep/data/archive
HITKEEP_BACKUP_PATH: /var/lib/hitkeep/data/backups
volumes:
- hitkeep_data:/var/lib/hitkeep/data
labels:
- "traefik.enable=true"
- "traefik.http.routers.hitkeep.rule=Host(`DEINE_DOMAIN`)"
- "traefik.http.routers.hitkeep.entrypoints=websecure"
- "traefik.http.routers.hitkeep.tls.certresolver=le"
- "traefik.http.services.hitkeep.loadbalancer.server.port=8080"
networks: [proxy]
volumes:
hitkeep_data: {}
networks:
proxy:
external: trueDie wichtigsten Stellen im Detail:
HITKEEP_PUBLIC_URList die öffentliche Adresse, unter der HitKeep erreichbar ist. Daraus baut die Oberfläche später den Tracking-Snippet und die Links. Sie muss exakt der URL entsprechen, unter der du HitKeep aufrufst – sonst kommst du in eine Login-Schleife.HITKEEP_TRUSTED_PROXIESist der Knackpunkt hinter einem Reverse Proxy: HitKeep vertraut in der Voreinstellung (*) demX-Forwarded-For-Header von jedem Absender – jeder Besucher könnte sich also eine fremde IP andichten.172.16.0.0/12schränkt das auf die Docker-Netze ein (dasproxy-Netz liegt darin, im Test etwa172.19.0.0/16), sodass nur noch Traefik die Besucher-IP setzen darf. Wichtig: Der Bereich muss die IP deines Proxys wirklich enthalten – passt er nicht, sieht HitKeep nur noch Traefiks Container-IP.loadbalancer.server.port=8080sagt Traefik, dass HitKeep intern auf Port 8080 lauscht. Der Container veröffentlicht selbst keine Ports nach außen – der Zugriff läuft ausschließlich über Traefik.- Die vier
_PATH-Variablen legen Datenbank, Daten, Archiv und Backups alle unterhalb von/var/lib/hitkeep/dataab – bewusst in einem Volume. Der Container läuft als Nicht-Root-Benutzer (UID 65532), und nur dieses eine Verzeichnis bringt das Image mit den passenden Rechten mit. Hängst du zusätzliche Volumes für Archiv und Backups an eigene Pfade, legt Docker sie root an, und HitKeep quittiert das im Log mitInitial backup run failedundpermission_denied.
Schritt 3: Stack starten und auf TLS warten
Starte den Container:
docker compose up -dPrüfe nach ein paar Sekunden den Status:
docker compose psDu solltest den Container als healthy sehen – HitKeep bringt einen eigenen Healthcheck mit:
NAME IMAGE COMMAND SERVICE CREATED STATUS PORTS
hitkeep pascalebeier/hitkeep:2.13.18 "hitkeep" hitkeep 40 seconds ago Up 40 seconds (healthy) 7946/tcp, 8080/tcpTraefik holt jetzt im Hintergrund das Let’s-Encrypt-Zertifikat für deine Domain. Prüfe von deinem eigenen Rechner aus, dass die Auslieferung des Tracking-Skripts steht:
curl -sI https://DEINE_DOMAIN/hk.jsErwartete Ausgabe (gekürzt) – Status 200 und ein text/javascript-Typ, aggressiv gecacht:
HTTP/2 200
content-type: text/javascript; charset=utf-8
cache-control: public, max-age=31536000, immutableAchtung
404 von Traefik oder eine Zertifikatswarnung, warte eine Minute (Let’s
Encrypt braucht kurz) und prüfe, dass der A-/AAAA-Record deiner Domain wirklich auf den Server
zeigt. Solange das Zertifikat nicht steht, lädt auch das Snippet im Browser nicht.Schritt 4: Admin-Konto anlegen
Rufe https://DEINE_DOMAIN im Browser auf. Beim allerersten Start begrüßt dich HitKeep mit der
Ersteinrichtung. Lege hier dein Administrator-Konto an – Name, E-Mail-Adresse und ein Passwort.
Nimm eine lange Passphrase oder ein per Passwortmanager erzeugtes Zufallspasswort; dieses Konto
sieht sämtliche Statistiken und darf nicht an einem schwachen Passwort hängen:

Tipp
Schritt 5: Website anlegen und Tracking-Code holen
Nach dem Login klickst du links oben bei Sites auf das Plus und legst deine Website an –
als Domain trägst du die Domain der Seite ein, die du messen willst (z. B. DEINE_WEBSITE).
Öffne dann über das </>-Symbol unter dem Site-Namen die Site-Einstellungen im Reiter
Tracking. Dort findest du oben den Live tracking verifier, der auf den ersten Treffer
wartet, und darunter unter Install HitKeep on … die Einbau-Varianten: Script tag, npm
(getippter Tracker für React/Vue/Angular/Astro), WordPress und Server-side. Alle melden in
dasselbe Dashboard; wir nehmen den Script-Tag:

Der einzubauende Code besteht aus einer einzigen Zeile. HitKeep braucht keine Site-ID im Snippet – die Zuordnung passiert automatisch über die Domain der Seite, auf der das Skript läuft:
<script async src="https://DEINE_DOMAIN/hk.js"></script>Hinweis
hk.js wird
von deiner HitKeep-Domain (DEINE_DOMAIN) geladen, zugeordnet wird der Treffer aber der Domain
der besuchten Seite (DEINE_WEBSITE). Beide dürfen unterschiedlich sein – die in HitKeep
angelegte Site muss nur zum Hostnamen der besuchten Seite passen.Automatisches Event-Tracking (ausgehende Klicks, Downloads, Formular-Absendungen) ist
standardmäßig aktiv. Unter Advanced options kannst du das Snippet anpassen – etwa „Web
Vitals" einschalten, um Ladezeiten (LCP, INP, CLS, FCP, TTFB) mitzumessen, oder „Collect DNT",
wenn du auch Besucher mit „Do Not Track" zählen willst. Aus Datenschutzsicht ist die
Voreinstellung (DNT respektieren) die sauberere. Wichtig: Diese Schalter werden nicht in
HitKeep gespeichert, sie schreiben nur zusätzliche data--Attribute in den Code-Schnipsel, den
du danach neu kopieren musst:
<script async src="https://DEINE_DOMAIN/hk.js" data-enable-web-vitals="true"></script>Schritt 6: Tracking-Code in die Website einbauen
Füge die Snippet-Zeile aus Schritt 5 in den <head> deiner Website ein – bei einer statischen
Seite direkt ins HTML-Template, bei einem CMS in den Kopfbereich bzw. ein „Custom HTML"-Feld.
Durch das async-Attribut blockiert das Skript den Seitenaufbau nicht.
Rufe danach eine Seite deiner Website im Browser auf. Der Live tracking verifier aus
Schritt 5 sollte innerhalb weniger Sekunden von „Waiting" auf einen ersten Treffer springen –
das ist die Bestätigung, dass die Kette Website → hk.js → HitKeep steht.
Schritt 7: Das Dashboard prüfen
Sobald Treffer eintrudeln, füllt sich das Dashboard. Unter Dashboard siehst du die Kennzahlen deiner Website – Live-Besucher, Seitenaufrufe, eindeutige Sitzungen, Absprungrate, Verweildauer und den Traffic-Verlauf:

Weiter unten listet Latest Hits die einzelnen Aufrufe mit Pfad, Zeitpunkt, Referrer und Gerät auf – hier siehst du auf einen Blick, über welche Suchmaschinen und Verweise deine Besucher kommen:

Damit steht deine selbst gehostete Statistik: Jeder Aufruf deiner Website landet direkt in deiner eigenen Datenbank, ohne Umweg über Dritte.
Schritt 8: Mehr als nur Seitenaufrufe
Für den Anfang reichen Seitenaufrufe und Referrer – HitKeep kann aber deutlich mehr, und die Bausteine dafür findest du in der linken Navigation. Ein paar, die sich für die meisten Seiten lohnen:
- Goals (Ziele): Definiere ein Ereignis als Ziel – etwa das Absenden eines Kontaktformulars oder einen Klick auf „Kaufen". So misst du nicht nur, wie viele kommen, sondern wie viele das tun, was du willst.
- Funnels (Trichter): Verkette mehrere Schritte (Startseite → Produktseite → Warenkorb) und sieh, an welcher Stelle Besucher abspringen.
- Events: Neben den automatisch erfassten Ereignissen (ausgehende Klicks, Downloads, Formulare) kannst du eigene Ereignisse aus deinem Frontend senden.
- Web Vitals: Schaltest du sie im Tracking-Reiter ein, siehst du echte Ladezeiten deiner Besucher (LCP, INP, CLS) statt synthetischer Laborwerte.
- UTM: Kampagnen-Parameter (
utm_source,utm_medium,utm_campaign) werden ausgewertet – praktisch, um Newsletter- oder Social-Reichweite auseinanderzuhalten. - Reporting: Lass dir eine Zusammenfassung regelmäßig per E-Mail schicken, statt selbst
ins Dashboard schauen zu müssen (dafür brauchst du die
HITKEEP_MAIL_*-Variablen mit den Zugangsdaten deines Mailservers).
Eine einzelne HitKeep-Instanz verwaltet außerdem beliebig viele Websites: Über das Plus bei Sites legst du weitere an, jede mit eigenem Snippet und eigenem Dashboard. Du brauchst also keinen zweiten Container, wenn du mehrere Projekte messen willst.
Wenn es nicht funktioniert
Der Live-Verifier bleibt auf „Waiting" / keine Treffer im Dashboard.
Prüfe im Browser (Entwicklertools → Netzwerk), ob hk.js überhaupt geladen wird und der
Sende-Request danach mit Status 2xx zurückkommt. Häufigste Ursachen: Das Snippet steckt nicht
im HTML, die in HitKeep angelegte Site-Domain passt nicht zum Hostnamen der besuchten Seite,
oder ein Ad-/Tracking-Blocker filtert den Aufruf. Da du unter deiner eigenen Domain hostest
(First-Party), greifen die meisten Blocker nicht – manche Listen kennen aber den Pfad hk.js.
Alle Besucher kommen scheinbar von einer einzigen IP, Land und Provider stehen auf „(Unknown)".
Dann greift HITKEEP_TRUSTED_PROXIES nicht: Der angegebene Bereich enthält die IP deines Proxys
nicht, und HitKeep wertet nur noch Traefiks Container-IP aus. Prüfe mit
docker network inspect proxy, in welchem Subnetz der Proxy liegt – 172.16.0.0/12 deckt die
üblichen Docker-Netze ab – und starte den Stack neu (docker compose up -d). Danach zählt wieder
die echte Client-IP aus dem X-Forwarded-For-Header.
Traefik liefert 404 oder 502.
Ein 404 heißt meist, dass die Router-Regel nicht greift – prüfe, dass Host(...) deine echte
Domain enthält und der Container im proxy-Netz hängt. Ein 502 deutet auf den falschen Port:
HitKeep lauscht intern auf 8080, deshalb muss loadbalancer.server.port=8080 gesetzt sein.
Nach dem Login landest du wieder auf der Anmeldeseite (Login-Schleife).
Das ist fast immer eine Diskrepanz bei HITKEEP_PUBLIC_URL: Der Wert muss exakt der Adresse
entsprechen, über die du HitKeep aufrufst (inklusive https://, ohne abschließenden Slash).
Korrigiere die Variable und starte den Container neu.
Der Container startet nicht bzw. ist nicht healthy.
Sieh in die Logs: docker compose logs -f hitkeep. Ein fehlendes oder leeres
HITKEEP_JWT_SECRET ist eine typische Startbremse – erzeuge eines wie in Schritt 1 und trage
es ein.
Dein Problem ist nicht dabei? Alle Fehlermeldungen durchsuchen →
Wartung & Backups
Updates: HitKeep bewegt sich in der 2.x-Reihe zügig weiter – zwischen 2.12.0 und 2.13.18 lagen
keine sieben Wochen. Schau also etwa monatlich in die
Releases. Für ein Update setzt du den neuen
Tag in der compose.yaml (ersetze 2.13.18 durch die neue Version) und ziehst ihn:
docker compose pull && docker compose up -dWeil die Daten in Volumes liegen, bleiben deine Statistiken dabei erhalten. Pinne die Version
bewusst auf einen festen Tag statt latest, damit ein Neustart dir nicht ungeplant eine neue
Hauptversion unterschiebt.
Backups: Deine gesamte Statistik steckt in einer eingebetteten DuckDB-Datei (hitkeep.db
samt Write-Ahead-Log hitkeep.db.wal) unter /var/lib/hitkeep/data. Sichere deshalb nicht eine
Einzeldatei, sondern das komplette Volume hitkeep_data regelmäßig – am saubersten mit
restic. HitKeep legt darin selbst stündlich einen Snapshot
unter backups/ ab und hält die letzten 24 vor; im Log siehst du das als
Database backup completed. Weil die Live-Dateien im laufenden Betrieb beschrieben werden,
sicherst du am konsistentesten entweder diese fertigen Snapshots oder das Volume, während der
Container kurz gestoppt ist (docker compose stop). Ein Backup, das du nie zurückgespielt
hast, ist nur ein Hoffnungsschimmer: Teste die Wiederherstellung einmal auf einem Testsystem.
Aufräumen: Die Datenbank wächst mit dem Traffic. Behalte die Größe der Volumes im Blick
(docker system df -v) und plane bei viel Traffic genügend Speicher ein.
Zuletzt aktualisiert: 09.09.2026
Feedback per E-Mail: feedback@serverkueche.de
Das könnte dir auch schmecken


