SSD Nodes Learn 🎉 VPS ab $5.50/Monat
Anleitungen Matt ConnorVon Matt Connor

OpenAnalytics auf einem VPS selbst hosten

OpenAnalytics benötigt ClickHouse, Postgres, Valkey, 4 GB RAM, 25 GB freien Speicher und vier DNS-Einträge. Hier folgen Installation und Speicherverbrauch.

Der Platzbedarf vor dem ersten Schritt

Für das Self-Hosting von OpenAnalytics benötigen Sie einen Linux-VPS mit etwa 4 GB RAM, 25 GB freiem Speicherplatz, Docker mit dem Compose-Plugin und vier DNS-Einträgen, die bereits auf den Server zeigen. Das ist die maßgebliche Voraussetzung. Sie gehört vor den ersten Befehl und nicht dahinter.

Der Stack besteht aus sechs Anwendungsdiensten und drei Datenspeichern. Postgres speichert die Steuerungsebene: Konten, Websites, API-Schlüssel und Freigabelinks. ClickHouse speichert die Rohereignisse und die Aggregationen, die das Dashboard abruft. Valkey läuft zweimal: einmal als dauerhafte Ereigniswarteschlange und einmal als Cache, dessen Verlust akzeptabel ist. Diese beiden Aufgaben benötigen entgegengesetzte Richtlinien für die Verdrängung von Einträgen. Nur ein Prozess, das Query-Gateway, darf ClickHouse lesen. Vor der Ausführung prüft es jede Abfragehülle auf eine Ed25519-Signatur.

Wenn Sie eine einzelne Binärdatei und eine einzelne Konfigurationsdatei erwartet haben, ist dies nicht die passende Lösung. GoatCounter ist in dieser Kategorie die Option mit einer einzelnen Binärdatei: eine Go-ausführbare Datei, standardmäßig SQLite und überhaupt keine externe Datenbank. Der umfangreichere Stack bietet Funnels, Web Vitals, die Umsatzzuordnung aus Ihrem eigenen Stripe-Konto und einen MCP-Server (Model Context Protocol). Der Beitrag Auswahl zwischen selbst gehosteten Analysewerkzeugen bewertet diesen Kompromiss. Diese Anleitung setzt voraus, dass Sie sich bereits entschieden haben.

Zuerst die DNS-Einträge auf die Box zeigen lassen

Vier Subdomains müssen vor dem Start auf die öffentliche IP-Adresse des Servers aufgelöst werden. Caddy fordert beim ersten Start Let's-Encrypt-Zertifikate an. Die Challenge schlägt fehl, wenn ein Name noch nicht aufgelöst wird.

  • app.example.com stellt das Dashboard bereit.
  • api.example.com stellt die API und die OAuth-Callbacks bereit.
  • c.example.com stellt den Collector und das Tracker-Skript bereit.
  • rt.example.com stellt den Echtzeitstream bereit.

Verwenden Sie vier A-Einträge oder einen A-Eintrag und drei darauf zeigende CNAME-Einträge. Bestätigen Sie die Auflösung mit dig +short app.example.com, bevor Sie fortfahren. Ein vor einer Minute hinzugefügter Name kann beim verwendeten Resolver von Let's Encrypt weiterhin als NXDOMAIN zwischengespeichert sein. Warten Sie daher einen ersten fehlgeschlagenen Zertifikatsversuch ab und prüfen Sie die Caddy-Logs. Eine erneute Ausführung der Installation beschleunigt die DNS-Propagation nicht.

OpenAnalytics mit Docker Compose selbst hosten

Checken Sie ein getaggtes Release aus. Im Standard-Branch findet die Entwicklung statt. Ein Release-Tag entspricht dagegen den tatsächlich veröffentlichten Images. Die folgenden Befehle setzen voraus, dass Docker und das Compose-Plug-in bereits installiert sind. Eine Anleitung dazu finden Sie unter Docker-Compose-Dienste auf einem VPS ausführen.

git clone https://github.com/OpenLabs-so/openanalytics
cd openanalytics
git checkout "$(git tag -l 'v*' --sort=-v:refname | sed '/-/d' | head -1)"
cd infra/selfhost
./generate-secrets.sh --domain example.com --email you@example.com --with-geoip
docker compose pull && docker compose up -d

sed '/-/d' in der Checkout-Zeile schließt Vorab-Tags aus. Dadurch verwenden Sie die neueste stabile Version statt eines Release Candidates. --with-geoip ruft während der Generierung die DB-IP-City-Datenbank ab. Wenn Sie diesen Schritt überspringen, enthält jedes Ereignis ein Null-Land. Die Geografieansicht bleibt dann vollständig leer. Sie können die Datenbank später hinzufügen, indem Sie infra/selfhost/geoip/fetch-dbip.sh ausführen, GEOIP_DB_PATH=/geoip/dbip-city-lite.mmdb in env/collector.env setzen und den Collector mit docker compose up -d --force-recreate collector neu erstellen. Die Datenbank wird monatlich aktualisiert. Wiederholen Sie den Abruf daher monatlich, damit Ihre Stadtdaten nicht veralten.

Sichern Sie die generierten Geheimnisse, bevor Sie fortfahren

Der Generator schreibt drei Dinge. .env enthält die Domainnamen und die Image-Referenzen. env/*.env enthält pro Dienst eine Datei mit Geheimnissen. docker-compose.override.yml enthält drei Ed25519-Schlüsselpaaren als YAML-Blockskalare, weil ein mehrzeiliger PEM-Inhalt nicht in einer Env-Datei gespeichert werden kann. Alle diese Dateien sind von Git ausgeschlossen. Keiner dieser Werte kann mit denselben Werten erneut generiert werden.

Kopieren Sie diese Dateien jetzt vom Rechner weg. Der Verlust hat jeweils konkrete Folgen:

  • Wenn Sie die Store-Passwörter verlieren, sind Sie aus Postgres und ClickHouse ausgesperrt. Sie können die Passwörter nur innerhalb der Container zurücksetzen.
  • Wenn Sie OA_CREDENTIAL_KEYRING verlieren, sind alle gespeicherten Anmeldedaten für Drittanbieter nicht wiederherstellbar. Jeder, der ein Stripe-Konto verbunden hat, muss es erneut verbinden.
  • Wenn Sie ANONYMOUS_IDENTITY_SECRET verlieren, wird die Besucheridentität neu bestimmt: Die Besucher von gestern zählen alle als neu, und die Unterbrechung ist in den Diagrammen sichtbar.
  • Wenn Sie AUTH_SECRET verlieren, werden alle Sitzungen ungültig. Daher müssen sich alle erneut anmelden.
  • Wenn Sie einen privaten Signaturschlüssel verlieren, tauschen Sie das Schlüsselpaar aus. Es gehen keine Daten verloren.

Zwei Geheimnisse müssen in jeweils zwei Dateien bytegenau identisch sein. ANONYMOUS_IDENTITY_SECRET steht in collector.env und worker.env, weil der Collector den Besucher-Hash berechnet und der Worker ihn schreibt. OA_CREDENTIAL_KEYRING steht in api.env und worker.env. Alle anderen Geheimnisse sind absichtlich genau einem Dienst zugeordnet. Ein Dienst, dem ein Geheimnis übergeben wird, das er nicht besitzen darf, beendet sich, statt zu starten.

Starten Sie den Stack und prüfen Sie ihn

grep OA_IMAGE .env
docker compose pull
docker compose up -d
docker compose logs -f migrate
docker compose ps

migrate wendet die PostgreSQL- und ClickHouse-Schemata an und wird anschließend beendet. Daher ist ein gestoppter migrate-Container der korrekte Endzustand. tracker-build kompiliert oa.js in ein Volume, das Caddy bereitstellt, und wird ebenfalls beendet. Alle anderen Dienste sollten in docker compose ps healthy lesen. Wenn ein Dienst in einer Schleife neu startet, schlägt fast immer die Umgebungsvalidierung fehl. Das Log gibt alle Probleme in einer Liste aus, statt jeweils eines pro Neustart. Die beiden häufigsten Ursachen sind eine leer gebliebene Variable, die abgelehnt wird und nicht als nicht gesetzt gilt, sowie ein Secret in der falschen Servicedatei.

Auf arm64 oder aus einem Branch gibt es keine veröffentlichten Images. In diesem Fall erstellen Sie sie lokal mit docker compose up -d --build. Ein Host mit 4 GB Arbeitsspeicher hat während dieses Builds keinen ausreichenden Speicher mehr. Fügen Sie zuerst Swap hinzu. Das ist nur während des Builds erforderlich:

fallocate -l 4G /swapfile && chmod 600 /swapfile && mkswap /swapfile && swapon /swapfile
echo '/swapfile none swap sw 0 0' >> /etc/fstab

Der Build dauert ungefähr zehn Minuten. Das Herunterladen dauert nur wenige Minuten. Deshalb gibt es die Release-Images.

Das erste Konto sofort anlegen

Öffnen Sie https://app.example.com. Eine Bereitstellung, bei der sich noch niemand angemeldet hat, zeigt kein Anmeldeformular an. Stattdessen wird angeboten, das erste Konto anzulegen. Dieses Konto verfügt dauerhaft über privilegierte Rechte. Nur dieses Konto kann den Bildschirm mit den Bereitstellungseinstellungen aufrufen. Sobald es existiert, antwortet die Route mit 409. Dadurch kann niemand nachträglich darauf zugreifen. Führen Sie diesen Schritt aus, sobald der Stack fehlerfrei läuft, und nicht erst in der folgenden Woche.

Tracker installieren

Fügen Sie im Dashboard eine Website hinzu. Anschließend wird Ihnen das Tag angezeigt. Die Struktur ist fest vorgegeben:

<script
  async
  src="https://c.example.com/oa.js"
  data-key="YOUR_TRACKING_KEY"
  data-collector="https://c.example.com"
></script>

Fügen Sie es in den <head>-Bereich der Seite ein. Der Tracking-Schlüssel ist absichtlich öffentlich und gehört daher in Ihren HTML-Code, wo ihn jeder lesen kann. Das Script installiert window.oa. Aufrufe wie oa("track", ...) werden zunächst von einem Stub zwischengespeichert und nach dem Laden der Datei abgearbeitet. Dadurch geht ein frühzeitig ausgelöstes benutzerdefiniertes Ereignis nicht verloren. Wenn window.oa auf der Seite bereits anderweitig verwendet wird, installiert der Tracker sich stattdessen als window.openanalytics.

Prüfen Sie anschließend die gesamte Verarbeitungskette:

curl -s https://c.example.com/oa.js -o /dev/null -w '%{http_code} %{size_download}\n'
curl -s https://api.example.com/health | head -c 200
docker compose logs --tail=50 worker | grep -i batch

Der erste Befehl sollte 200 und einige Kilobyte ausgeben. Laden Sie eine Seite Ihrer Website. Suchen Sie anschließend innerhalb weniger Sekunden im Worker-Log nach einer Batch-Zeile. Der Collector antwortet mit 202, sobald er ein Ereignis annimmt. 202 bedeutet, dass das Ereignis in die Warteschlange gestellt wurde, nicht dass es gespeichert ist. Der Worker schreibt die Ereignisse in ClickHouse. Werden Ereignisse angenommen, erscheinen aber nicht im Dashboard, ist der Worker blockiert. Eine kontinuierlich wachsende Valkey-Warteschlangentiefe bestätigt das. Häufige Ursachen sind falsche ClickHouse-Zugangsdaten in worker.env oder eine fehlende Berechtigung für eine Tabelle, die eine Migration gerade hinzugefügt hat.

Collector öffentlich halten und das Dashboard mit Authentifizierung schützen

Caddy ist in der Compose-Datei enthalten und beschafft selbstständig Zertifikate für alle vier Namen. Im Standardpfad ist daher keine Proxy-Konfiguration erforderlich. Wenn auf dem System bereits ein Nginx-Reverse-Proxy läuft, schalten Sie stattdessen den mitgelieferten infra/selfhost/nginx.conf.example vor den Stack und behalten Sie dessen Header-Verarbeitung bei:

proxy_set_header X-Real-IP $remote_addr;
proxy_set_header CF-Connecting-IP "";
proxy_set_header True-Client-IP "";
proxy_set_header Fly-Client-IP "";

Der Collector leitet den täglichen Besucher-Hash aus der Client-IP-Adresse ab. Deshalb muss er diese Adresse aus der Verbindung beziehen und darf sie niemals aus einem Header übernehmen. Wenn Sie CF-Connecting-IP von einem nicht vertrauenswürdigen Hop weiterreichen, kann jeder Aufrufer eine beliebige Adresse angeben. Dadurch werden die Geolokalisierung verfälscht und gleichzeitig die Besucherzahlen erhöht.

Der Zugriff wird sauber nach Hostnamen getrennt. c. und rt. müssen für jeden Besucher jeder gemessenen Website erreichbar sein. Schalten Sie daher niemals eine Basic-Authentifizierung oder eine IP-Allowlist vor diese beiden Hostnamen. app. und api. müssen nur für angemeldete Benutzer erreichbar sein. Die Authentifizierung der Anwendung schützt das Dashboard. Die Anmeldung per Passwort ist standardmäßig über AUTH_PASSWORD_SIGNIN=enabled in env/api.env aktiviert. Die Google- oder GitHub-Schaltflächen werden nur angezeigt, wenn für den jeweiligen Anbieter sowohl die Client-ID als auch das Client-Secret vorhanden sind. Magic Links benötigen einen Mail-Transport. Ohne diesen schreibt die API den Versand lediglich in eine Outbox. Dadurch wird nichts zugestellt und es tritt kein Fehler auf.

Eine Einstellung entscheidet darüber, ob das Dashboard überhaupt funktioniert. AUTH_TRUSTED_ORIGINS in env/api.env muss exakt dem Ursprung des Dashboards entsprechen. Bei einem falschen oder fehlenden Wert sendet die API keine CORS-Header (Cross-Origin Resource Sharing). Der Browser lehnt dann jeden Aufruf ab. Das Dashboard rendert sein Layout, zeigt aber keine Daten an, während docker compose ps einen fehlerfreien Zustand meldet.

Kümmern Sie sich während der Bearbeitung der Proxy-Konfiguration auch um automatisierten Datenverkehr. Crawler greifen wie alle anderen Clients auf den Collector zu. Ihre Seitenaufrufe landen in ClickHouse und fließen in Ihre Kennzahlen ein. KI-Crawler auf dem Server blockieren hält einen Teil dieses Datenverkehrs von der Datenbank fern, bevor er sowohl die Genauigkeit als auch den Speicherbedarf beeinträchtigt.

Was „cookieless“ hier bedeutet und welche Kosten damit verbunden sind

Es gibt kein Cookie. Die Besucheridentität ist ein gesalzener Hash. Das Salt wird täglich gewechselt. Rohdaten zu IP-Adressen werden nie gespeichert. Die Geolokalisierung erfolgt lokal anhand der DB-IP-Datei auf Ihrer eigenen Festplatte. Daher verlässt keine Abfrage zu einem Besucher den Host.

Der Vorteil besteht darin, dass auf dem Gerät des Besuchers kein Identifikator gespeichert wird. Genau das führt dazu, dass ein Tracker unter die Einwilligungsregeln der EU-ePrivacy-Richtlinie fällt. Aggregierte Setups wie dieses werden aus diesem Grund häufig ohne Einwilligungsbanner betrieben. Die DSGVO gilt weiterhin für alle Daten, die Sie speichern, und für die Dauer ihrer Speicherung. Ob dies in Ihrem Fall zulässig ist, entscheidet Ihre eigene Rechtsberatung, nicht eine README-Datei.

Der Nachteil ist, dass sich Identitäten nicht über mehrere Tage hinweg zuordnen lassen. Durch den Wechsel des Salt wird eine Person, die am Montag und erneut am Mittwoch die Website besucht, absichtlich als zwei Besucher gezählt. Dafür gibt es keine Umgehung. Die täglichen Besucherzahlen sind zuverlässig. Die wöchentlichen und monatlichen Besucherzahlen werden aus den täglichen Zahlen gebildet und überschätzen daher die Reichweite. Eine Kennzahl für „wiederkehrende Besucher“ über längere Zeiträume misst deshalb nicht das, was ihre Bezeichnung vermuten lässt. Sitzungen und Besuchsverläufe sind innerhalb eines einzelnen Tages zuverlässig. Die Rotation von ANONYMOUS_IDENTITY_SECRET hat denselben Effekt wie ein Tageswechsel. Behandeln Sie diese Rotation daher als Datenänderung und nicht als routinemäßige Wartung.

Der Collector berücksichtigt Do Not Track und Global Privacy Control. Dabei handelt es sich um das Browsersignal, mit dem eine Website angewiesen wird, personenbezogene Daten nicht zu verkaufen oder weiterzugeben. Das Script-Tag enthält eigene Schalter für denselben Zweck: data-respect-gpc, data-respect-dnt und data-require-consent. data-require-consent hält die gesamte Datenerfassung zurück, bis eine Einwilligung erteilt wurde, und speichert die Antwort in localStorage unter dem Schlüssel oa.consent. Mit data-storage="none" deaktivieren Sie den Browser-Speicher vollständig.

Warum die Festplatte nach sechs Monaten voll ist

Das ist es, was eine selbst gehostete Analytics-Instanz außer Betrieb setzt. Die Ereignisdaten sind normalerweise nicht die Ursache.

Beginnen Sie mit den Images. Ein Release veröffentlicht zehn davon. Zusammen belegen sie etwa 13 GB auf der Festplatte. Bei einem Upgrade werden die neuen Images abgerufen, bevor die alten gelöscht werden. Daher sind vorübergehend zwei Generationen vorhanden. Das macht den größten Teil des Bedarfs von 25 GB aus, bevor auch nur ein einziger Seitenaufruf eingeht.

Dann kommen die Snapshots hinzu. snapshot.sh stoppt den Stack, archiviert beide Daten-Volumes einschließlich aller Secrets und startet den Stack anschließend neu. Hier sind nur Kopien im gestoppten Zustand sicher, weil ClickHouse Parts im Hintergrund zusammenführt und eine während einer Zusammenführung erstellte Kopie nicht konsistent ist. upgrade.sh erstellt vor jedem Upgrade automatisch einen Snapshot. Dadurch sammeln sich die Archive auf derselben Festplatte an, bis Sie ihre Anzahl begrenzen.

./snapshot.sh create --label before-something-risky
./snapshot.sh list
./snapshot.sh --keep 3

Wenn der Host den Kapazitätsgrenzwert fast erreicht hat, geben Sie vor dem Upgrade die vorherige Generation frei. Das ist während des laufenden Betriebs des Stacks sicher, weil Images von laufenden Containern weiterhin referenziert werden:

docker image prune -a -f

Dann kommen die Ereignisdaten selbst. ClickHouse komprimiert spaltenbasierte Daten stark. Das Volumen der Rohdaten wächst daher langsamer als von den meisten Benutzern erwartet. Die vom Dashboard gelesenen Rollup-Tabellen sind im Vergleich zur Rohdatentabelle klein. Messen Sie, statt zu schätzen:

docker system df -v
docker compose exec clickhouse df -h /var/lib/clickhouse

Für die Angabe pro Tabelle führen Sie diesen Befehl mit den ClickHouse-Anmeldedaten aus, die der Generator unter infra/selfhost/env/ geschrieben hat:

SELECT table, formatReadableSize(sum(bytes_on_disk)) AS size, sum(rows) AS row_count
FROM system.parts
WHERE active
GROUP BY table
ORDER BY sum(bytes_on_disk) DESC;

Ermitteln Sie diesen Wert in der ersten Woche und erneut in der vierten Woche. Zwei Messpunkte ergeben eine Wachstumsrate. Anhand der Wachstumsrate können Sie bestimmen, wann das Volume vergrößert werden muss. Die Self-Hosting-Anleitung dokumentiert für Rohdaten bis August 2026 keinen Schalter für Aufbewahrung oder Time-to-Live. Dimensionieren Sie die Festplatte daher anhand der gemessenen Rate. Gehen Sie nicht davon aus, dass alte Zeilen automatisch ablaufen.

Eine Falle beim Löschen sollten Sie kennen, bevor sie Probleme verursacht. Beim Löschen einer Site oder eines Kontos wird ein Auftrag für den Worker eingereiht. Dieser Worker benötigt gesetzte Werte für CLICKHOUSE_MAINTENANCE_USER und CLICKHOUSE_MAINTENANCE_PASSWORD. Außerdem muss in ClickHouse ein passender Benutzer oa_maintenance vorhanden sein. Ohne diese Voraussetzungen bleibt der Löschauftrag dauerhaft in der Warteschlange. Die Site verschwindet aus dem Dashboard, aber alle Zeilen bleiben auf der Festplatte. Dadurch sieht es nach einer Bereinigung aus, ohne dass Speicherplatz freigegeben wird.

Upgrades und die drei Kosten

git fetch --tags
git checkout "$(git tag -l 'v*' --sort=-v:refname | sed '/-/d' | head -1)"
cd infra/selfhost
./upgrade.sh

upgrade.sh gibt vor dem Start drei Kosten aus. Der Ausfall ist real: Während der Collector nicht läuft, gehen ausgelöste Ereignisse verloren, weil der Tracker sie nicht erneut versucht. Ein Rollback führt zu Datenverlust, weil rollback.sh --to backups/<snapshot> beide Speicher vollständig ersetzt und jede Zeile verwirft, die nach dem Erstellen dieses Snapshots geschrieben wurde. Der Speicherplatz ist die dritte Kostenart. Gemeint ist der oben beschriebene Snapshot-Bestand.

Zwei Regeln für den Neustart werden leicht verwechselt. Starten Sie das Query-Gateway vor der API, weil eine neuere API Query-Felder sendet, die ein älteres Gateway ablehnt. ClickHouse muss außerdem neu erstellt und nicht nur neu gestartet werden, weil docker compose restart die ursprüngliche Umgebung des Containers wiederverwendet und Ihre Änderung stillschweigend ignoriert:

docker compose up -d --force-recreate clickhouse

Das Dashboard weist dieselbe Fehlerquelle auf. Die drei NEXT_PUBLIC_*-Ursprünge in env/web.env werden in das Browser-Bundle kompiliert und beim Start des Containers eingesetzt. Wenn ein Dashboard den falschen Hostnamen verwendet, beheben Sie das mit docker compose up -d --force-recreate web und niemals mit restart. Das Log des Webcontainers gibt die beim Start verwendeten Ursprünge aus. So lässt sich am schnellsten prüfen, ob die Änderung übernommen wurde.

Wenn ClickHouse nach einer Konfigurationsänderung den Start verweigert, lesen Sie die erste Logzeile. Eine mit oa-entrypoint: beginnende Zeile zeigt, dass der Entrypoint einen von Ihnen gesetzten Wert ablehnt. Andernfalls ist die Konfigurationsdatei normalerweise ungültiges XML. Die häufigste Ursache ist ein doppelter Bindestrich in einem XML-Kommentar. Das ist dort nicht zulässig.

AGPL-3.0 und der Name

Der Code steht unter der Lizenz AGPL-3.0. Wenn Sie ihn unverändert für Ihre eigenen Websites betreiben, entsteht dadurch keinerlei Veröffentlichungspflicht. Diese Pflicht beginnt, sobald Sie den Code ändern und die geänderte Version als Netzwerkdienst betreiben: Die Lizenz verpflichtet Sie dann, den Nutzern dieses Dienstes den geänderten Quellcode anzubieten. Das gilt auch, wenn Sie Kunden Dashboards auf Ihrer Instanz bereitstellen oder den Code in ein Produkt aufnehmen, das Sie verkaufen. Wenn Sie Ihre Änderungen in einem öffentlichen Fork pflegen, erfüllen Sie diese Pflicht ohne weitere Schritte.

Die Marke ist vom Code getrennt. Der Name "OpenAnalytics" und die gehostete Domain des Projekts identifizieren die von den Autoren betriebene Instanz und sind nicht Bestandteil der Lizenzeinräumung. Ihre Bereitstellung führt die Software aus, ohne die Marke zu übernehmen. Geben Sie dem Dienst daher einen eigenen Namen, bevor Sie ihn zahlenden Kunden bereitstellen.

FAQ

Kann ich OpenAnalytics auf einem VPS mit 1 GB ausführen?

Nein. Das Projekt benötigt etwa 4 GB RAM und 25 GB freien Speicherplatz, weil eine Bereitstellung neben Postgres, ClickHouse und zwei Valkey-Instanzen sechs Anwendungsdienste ausführt. ClickHouse allein ist kein kleiner Prozess. Auf einem System mit 1 GB starten die Container, anschließend beendet der Out-of-Memory-Killer des Kernels einen von ihnen, normalerweise ClickHouse. Wenn ein Tarif mit 1 GB die feste Vorgabe ist, verwenden Sie ein Tool mit einer einzelnen Binärdatei wie GoatCounter. Es läuft mit SQLite ohne externe Datenbank.

Das ist eine Frage für Ihren Rechtsberater. Die technischen Fakten sprechen jedoch für Sie. Es gibt kein Cookie. Die Besucheridentität wird als täglich wechselnder Salted Hash gespeichert. Rohe IP-Adressen werden nie gespeichert. Daher werden keine dauerhaften Daten zur Identifizierung des Besuchers geschrieben. Die DSGVO regelt weiterhin, welche Daten Sie speichern und wie lange Sie sie aufbewahren. Wenn Sie die Datenerfassung ausdrücklich von einer Einwilligung abhängig machen möchten, setzen Sie data-require-consent im Script-Tag. Der Tracker erfasst dann nichts, bis die Einwilligung erteilt wurde, und speichert die Antwort in localStorage unter oa.consent.

Warum liefern Ereignisse 202 zurück, erscheinen aber nie im Dashboard?

202 bedeutet, dass der Collector das Ereignis angenommen und in die Warteschlange gestellt hat. Es bedeutet nicht, dass er es gespeichert hat. Der Worker leert diese Warteschlange nach ClickHouse. Ein leeres Dashboard bei erfolgreichen Anfragen weist daher auf den Worker hin. Lesen Sie docker compose logs --tail=50 worker und überwachen Sie die Länge der Valkey-Warteschlange. Eine weiterhin wachsende Warteschlange bedeutet, dass der Worker blockiert ist. Die häufigsten Ursachen sind falsche ClickHouse-Zugangsdaten in worker.env oder eine fehlende Berechtigung für eine Tabelle, die durch eine kürzlich ausgeführte Migration erstellt wurde.

Warum ist das Dashboard leer, obwohl jeder Container fehlerfrei läuft?

Prüfen Sie zuerst AUTH_TRUSTED_ORIGINS in env/api.env. Der Wert muss exakt mit dem Ursprung des Dashboards übereinstimmen. Ist das nicht der Fall, sendet die API keine CORS-Header. Der Browser verweigert dann jeden Aufruf. Sie sehen eine funktionierende Oberfläche ohne Daten. Prüfen Sie als Nächstes die drei NEXT_PUBLIC_*-Werte in env/web.env. Sie werden beim Start des Web-Containers eingesetzt. Für eine Korrektur ist docker compose up -d --force-recreate web erforderlich, weil ein einfacher Neustart die alten Werte beibehält.

Verhindert AGPL-3.0, dass ich dies Kunden anbiete?

Nein, die Lizenz stellt eine Bedingung. Wenn Sie den Code unverändert ausführen, schulden Sie niemandem etwas. Wenn Sie ihn ändern und die geänderte Version als Dienst für andere Personen betreiben, müssen Sie diesen Benutzern Ihren geänderten Quellcode anbieten. Ein öffentliches Fork erfüllt diese Vorgabe. Der Name „OpenAnalytics“ ist nicht zusammen mit dem Code lizenziert. Alles, was Sie verkaufen, benötigt daher einen eigenen Namen.