Matomo cookielos selbst hosten: Analytics ohne Consent-Banner
Matomo 5.12 mit Docker & Traefik aufsetzen: datenschutzfreundliche Web-Analytics mit IP-Anonymisierung, ganz ohne Google und ohne Cookie-Banner.
Inhaltsverzeichnis
Google Analytics kennt jeden deiner Besucher besser als du selbst – und schickt die Daten in die USA. Mit Matomo holst du dir die Web-Analytics zurück auf den eigenen Server: DSGVO-konform, IP-anonymisiert und in vielen Fällen ganz ohne Cookie-Banner.
Was bauen wir?
Am Ende läuft Matomo 5.12 in Docker hinter deinem Traefik-Reverse-Proxy, erreichbar unter deiner eigenen (Sub-)Domain mit gültigem HTTPS-Zertifikat. Als Datenbank kommt MariaDB 11.4 dazu – beides in einem compose.yaml. Du bekommst ein vollwertiges Analytics-Dashboard, das Besucherzahlen, Herkunft, Geräte und beliebte Seiten auswertet – die Daten liegen ausschließlich auf deinem Server.
Der eigentliche Gewinn gegenüber Google Analytics ist der Datenschutz: Wir kontrollieren die IP-Anonymisierung und konfigurieren Matomo so, dass es ohne Cookies auskommt. Das ist die technische Grundlage dafür, dass du in vielen Fällen auf einen nervigen Consent-Banner verzichten kannst. Matomo ist dabei das Vollpaket – wenn du nur wissen willst, welche Seiten wie oft aufgerufen werden, reicht auch das deutlich schlankere HitKeep.
Hinweis
Voraussetzungen
- Ein abgesicherter Server mit Debian 13 und einem sudo-Benutzer
- Docker & Docker Compose installiert
- Ein laufender Traefik-Reverse-Proxy mit dem externen Netzwerk
proxyund dem Zertifikats-Resolverle– Matomo hängt sich dort ein - Eine (Sub-)Domain, deren A-/AAAA-Record auf deinen Server zeigt, z. B.
statistik.DEINE-DOMAIN.de - Eine funktionierende Backup-Strategie mit Restic – Analytics-Daten sammeln sich über Jahre an, die willst du nicht verlieren
Matomo ist genügsam: Für eine kleine bis mittlere Website reicht der VPS 1000 locker. Erst bei sehr viel Traffic oder wenn viele andere Dienste mitlaufen, lohnt der Blick auf mehr RAM – unser Server-Rechner hilft dir bei der Einschätzung.
VPS 1000 G12
4 vCore · 8 GB RAM · 256 GB NVMe
ab 10,36 €/Monat
Reicht für Matomo neben ein paar weiteren kleinen Diensten.
💶 5 € Gutschein für netcup-Neukunden:36nc17844976032
(nur Neukunden, keine Domains)
Schritt für Schritt
Schritt 1: Projektordner anlegen und Netzwerk prüfen
Wir legen für Matomo einen eigenen Ordner unter /opt an – so bleibt jeder Dienst sauber getrennt:
mkdir -p /opt/matomo && cd /opt/matomoMatomo muss ins selbe Docker-Netzwerk wie Traefik, damit der Proxy den Container erreicht. Prüfe, dass das Netzwerk proxy aus dem Traefik-Tutorial existiert:
docker network ls | grep proxyDu solltest eine Zeile mit proxy sehen. Falls nicht, richte zuerst Traefik ein – ohne den Proxy bekommt Matomo kein Zertifikat.
Schritt 2: Passwörter in eine .env auslagern
Die Datenbank-Passwörter gehören nicht ins compose.yaml, sondern in eine separate .env. Wir lassen sie von openssl zufällig erzeugen:
{
echo "DB_PASSWORD=$(openssl rand -hex 16)"
echo "DB_ROOT_PASSWORD=$(openssl rand -hex 16)"
} > .env
chmod 600 .envchmod 600 sorgt dafür, dass nur root die Datei lesen kann. Wirf einmal einen Blick hinein, damit du die Werte kennst:
cat .envDB_PASSWORD=b51024e3f9a7c8d1e2f3a4b5c6d7e8f9
DB_ROOT_PASSWORD=1a2b3c4d5e6f70819a0b1c2d3e4f5061Schritt 3: Die compose.yaml schreiben
Lege die Datei /opt/matomo/compose.yaml mit folgendem Inhalt an. Ersetze im Traefik-Label statistik.DEINE-DOMAIN.de durch deine echte (Sub-)Domain:
services:
db:
image: mariadb:11.4
container_name: matomo-db
command: --max-allowed-packet=64MB
environment:
MARIADB_DATABASE: matomo
MARIADB_USER: matomo
MARIADB_PASSWORD: ${DB_PASSWORD}
MARIADB_ROOT_PASSWORD: ${DB_ROOT_PASSWORD}
volumes:
- db:/var/lib/mysql
networks: [intern]
restart: unless-stopped
app:
image: matomo:5.12-apache
container_name: matomo
environment:
MATOMO_DATABASE_HOST: db
MATOMO_DATABASE_ADAPTER: mysql
MATOMO_DATABASE_USERNAME: matomo
MATOMO_DATABASE_PASSWORD: ${DB_PASSWORD}
MATOMO_DATABASE_DBNAME: matomo
volumes:
- app:/var/www/html
depends_on: [db]
networks: [proxy, intern]
restart: unless-stopped
labels:
- "traefik.enable=true"
- "traefik.http.routers.matomo.rule=Host(`statistik.DEINE-DOMAIN.de`)"
- "traefik.http.routers.matomo.entrypoints=websecure"
- "traefik.http.routers.matomo.tls.certresolver=le"
- "traefik.http.services.matomo.loadbalancer.server.port=80"
networks:
proxy:
external: true
intern:
external: false
volumes:
db:
app:Das Wichtigste an dieser Datei:
- Zwei Netzwerke, bewusst getrennt. Nur der
app-Container hängt improxy-Netz und ist damit von außen erreichbar. Die Datenbank liegt im internen Netzinternund ist nicht über Traefik ansprechbar – genau richtig. - Die
MATOMO_DATABASE_*-Variablen füllen den Web-Installer im nächsten Schritt automatisch vor. Du musst die DB-Daten also nicht noch einmal von Hand eintippen. max-allowed-packet=64MBempfiehlt Matomo für die Datenbank, sonst kann der Import großer Berichte abbrechen.- Kein Port nach außen. Weder Matomo noch die DB veröffentlichen einen Host-Port. Der einzige Weg hinein führt über Traefik und damit über HTTPS.
Schritt 4: Den Stack starten
docker compose up -dBeim ersten Start lädt Docker die Images (rund 310 MB Download, entpackt gut 1,3 GB) und legt die Volumes an. Prüfe danach den Status:
docker compose psNAME IMAGE COMMAND SERVICE CREATED STATUS PORTS
matomo matomo:5.12-apache "/entrypoint.sh apac…" app 15 seconds ago Up 13 seconds 80/tcp
matomo-db mariadb:11.4 "docker-entrypoint.s…" db 15 seconds ago Up 14 seconds 3306/tcpBeide Container sollten Up sein. Traefik erkennt den neuen Container automatisch über die Labels und holt im Hintergrund ein Let’s-Encrypt-Zertifikat für deine Domain. Das dauert meist nur wenige Sekunden. Prüfe von deinem eigenen Rechner aus, ob Matomo antwortet:
curl -sI https://statistik.DEINE-DOMAIN.de | head -1HTTP/2 200Ein HTTP/2 200 bedeutet: Zertifikat steht, Traefik routet, Matomo läuft. Falls stattdessen ein Zertifikatsfehler kommt, gib Traefik ein paar Sekunden mehr – siehe „Wenn es nicht funktioniert".
Installer sofort abschließen
Schritt 5: Den Web-Installer durchklicken
Öffne https://statistik.DEINE-DOMAIN.de im Browser. Matomo begrüßt dich mit einem achtstufigen Einrichtungsassistenten.

Klicke dich durch die ersten Schritte:
- Willkommen → Weiter.
- Systemprüfung: Matomo prüft PHP-Version, Erweiterungen und Schreibrechte. Dank des offiziellen Images bleibt die Liste fehlerfrei. Eine gelbe Warnung siehst du trotzdem: Erzwungene SSL Verbindung. Sie ist hier normal und kein Grund abzubrechen – Matomos eigene Option
force_sslist schlicht noch nicht gesetzt, ausgeliefert wird trotzdem nur über HTTPS. Wir räumen sie in Schritt 7 aus. → Weiter. - Datenbank einrichten: Die Felder sind bereits ausgefüllt (das erledigen die
MATOMO_DATABASE_*-Variablen aus dercompose.yaml). Kontrolliere kurz, dass als Serverdbsteht, und klicke Weiter. - Tabellen anlegen: Matomo legt sein Datenbankschema an. → Weiter.
Jetzt legst du deinen Hauptadministrator an. Wähle einen Benutzernamen, ein starkes Passwort und eine echte E-Mail-Adresse (über sie kommen Sicherheits- und Update-Hinweise).
Danach richtest du die erste Website ein, die du tracken willst. Neben Name und URL ist die Zeitzone ein Pflichtfeld: Lässt du sie auf der Vorauswahl stehen, weist das Formular dich mit Zeitzone der Webseite ist nicht gültig zurück. Sie entscheidet, wann für deine Berichte ein neuer Tag beginnt – für eine deutsche Website also Deutschland – Berlin.

Schritt 6: Den Tracking-Code einbauen
Im vorletzten Schritt zeigt dir Matomo den JavaScript-Tracking-Code. Das ist das kleine Snippet, das in jede Seite deiner Website gehört – idealerweise direkt vor </head>:

<!-- Matomo -->
<script>
var _paq = window._paq = window._paq || [];
_paq.push(['disableCookies']);
_paq.push(['trackPageView']);
_paq.push(['enableLinkTracking']);
(function() {
var u="//statistik.DEINE-DOMAIN.de/";
_paq.push(['setTrackerUrl', u+'matomo.php']);
_paq.push(['setSiteId', '1']);
var d=document, g=d.createElement('script'), s=d.getElementsByTagName('script')[0];
g.async=true; g.src=u+'matomo.js'; s.parentNode.insertBefore(g,s);
})();
</script>
<!-- End Matomo Code -->Die Zeile _paq.push(['disableCookies']); (im Original-Snippet nicht enthalten) haben wir bewusst ergänzt: Damit verzichtet Matomo komplett auf Cookies – ein wichtiger Baustein für den Betrieb ohne Consent-Banner. Betreibst du deine Website mit einem CMS wie WordPress, gibt es fertige Plugins („Matomo for WordPress", „Connect Matomo"), die das Snippet automatisch einbinden. Nach dem letzten Schritt („Fertig") meldest du dich mit deinem eben angelegten Konto an und landest im Dashboard.

Das Dashboard bündelt die wichtigsten Berichte: Besuche in Echtzeit, den Graph der letzten Besuche, die Besucherübersicht, eine Besucherkarte und unter Kanaltypen die Herkunft der Besucher (Suchmaschine, Direktzugriff, Verweis). Über das Menü links kommst du tiefer – Besucher (Geräte, Browser, Standort), Verhalten (Seiten, Ein- und Ausstiege) und Akquisition (welche Kanäle Besucher bringen). Genau die Fragen, die Google Analytics beantwortet – nur eben auf deinem Server.
Admin-Konto absichern
Schritt 7: Datenschutz-Einstellungen prüfen (der wichtige Teil)
Matomo 5.12 startet datenschutzfreundlicher, als viele erwarten: Die IP-Anonymisierung ist ab Werk aktiv. Trotzdem gehst du die Seite einmal durch – erstens, um es mit eigenen Augen gesehen zu haben, zweitens, weil dort ein Schalter liegt, der dein cookieloses Tracking wirklich absichert. Öffne oben rechts Verwaltung (Zahnrad) → im Menü links Privatsphäre → Daten anonymisieren.

Drei Stellschrauben sind entscheidend:
- Anonymisiere die IP-Adresse von Besuchern: steht schon auf Ja, maskiert werden standardmäßig 2 byte(s) – aus
203.0.113.45wird also203.0.xxx.xxx(Matomo markiert diese Stufe selbst als Empfohlen). Kontrolliere nur, dass das so geblieben ist; damit ist der einzelne Besucher nicht mehr identifizierbar. - Tracking ohne Cookies erzwingen: einschalten. Matomo ergänzt dann
matomo.jsserverseitig um den passenden Code und ignoriert Tracking-Cookies zusätzlich beim Empfang. Das wirkt auch dann noch, wenn irgendwo doch das Original-Snippet ohnedisableCookieslandet – ein Sicherheitsnetz für den Punkt, an dem dein Consent-Banner-Verzicht hängt. - „Do Not Track": liegt unter Privatsphäre → Benutzer Opt-Out. Matomo stuft die Unterstützung inzwischen selbst als veraltet ein – weil Browser das Signal ungefragt senden oder gar nicht mehr unterstützen, „empfehlen wir nicht mehr, diese Option zu aktivieren". Verlass dich also nicht darauf. Der belastbare Weg steht auf derselben Seite: der Opt-out-Baustein (iframe oder eigenes Formular), den du in deine Datenschutzerklärung einbaust.
Tipp
Bleibt noch der Schalter, den die Systemprüfung aus Schritt 5 angemahnt hat: force_ssl. Er weist unverschlüsselte Zugriffe in Matomo selbst ab, statt sich allein auf Traefik zu verlassen. In der Oberfläche gibt es ihn nicht, er steht in Matomos config/config.ini.php im Volume:
cd /opt/matomo
docker compose exec -u www-data app sed -i '/^\[General\]/a force_ssl = 1' config/config.ini.phpsed hängt die Zeile force_ssl = 1 direkt unter den Abschnitt [General]; -u www-data sorgt dafür, dass die Datei ihrem bisherigen Besitzer gehört und Matomo sie weiter schreiben kann. Lade danach das Dashboard neu – unter Verwaltung → Diagnose → Systemprüfung ist die Warnung Erzwungene SSL Verbindung verschwunden.
Schritt 8: Berichte per Cron archivieren
In der Grundeinstellung berechnet Matomo seine Berichte „on the fly", sobald jemand das Dashboard öffnet. Das wird bei mehr Traffic langsam und ist offiziell nicht empfohlen. Besser: ein Cronjob rechnet die Berichte regelmäßig im Hintergrund vor.
Trage dazu auf dem Host einen Cronjob ein, der alle 15 Minuten das Archivierungskommando im Container ausführt:
crontab -eFüge diese Zeile hinzu (Domain anpassen):
*/15 * * * * cd /opt/matomo && docker compose exec -T -u www-data app ./console core:archive --url=https://statistik.DEINE-DOMAIN.de >> /opt/matomo/archive.log 2>&1Das Log landet bewusst in /opt/matomo/archive.log und nicht unter /var/log: Läuft dein Cron als sudo-Benutzer (nicht als root), scheitert ein Schreibzugriff auf /var/log still. In /opt/matomo hast du Schreibrechte, und du findest das Log direkt beim Projekt.
Anschließend schaltest du die alte Betriebsart ab: Verwaltung → Allgemeine Einstellungen → Archivierungseinstellungen, dort „Berichte archivieren, wenn diese im Browser angezeigt werden" auf Nein stellen und speichern. So bleibt das Dashboard auch bei viel Traffic schnell – und die Systemprüfung meldet nicht mehr, dass Browser- und Cron-Archivierung gleichzeitig laufen.
Wenn es nicht funktioniert
Der Browser zeigt einen Zertifikatsfehler oder 404 page not found. Traefik hat das
Let’s-Encrypt-Zertifikat noch nicht geholt, oder der DNS-Record zeigt nicht auf den Server. Prüfe
mit dig statistik.DEINE-DOMAIN.de, dass die IP stimmt, und sieh in die Traefik-Logs. Den genauen
Container-Namen aus deinem Traefik-Setup findest du mit docker ps | grep traefik, dann docker logs <container-name> (bei uns z. B. docker logs traefik-traefik-1). Die HTTP-Challenge
scheitert, wenn Port 80 nicht von außen erreichbar ist – kontrolliere deine
Firewall und die
netcup-Firewall.
Der Installer meldet SQLSTATE... Connection refused oder hängt bei der Datenbank. MariaDB war
beim ersten Start noch nicht bereit. Gib der DB einen Moment und lade die Seite neu. Prüfe mit
docker compose logs db, ob dort ready for connections steht. Erscheint stattdessen ein
Zugangsfehler, passen DB_PASSWORD in der .env und die bereits angelegte DB nicht mehr zusammen –
dann hilft ein sauberer Neustart mit docker compose down -v (Achtung: löscht die Daten) und
docker compose up -d.
Warnung „Es sieht so aus, als ob die trusted_hosts-Einstellung nicht korrekt ist". Matomo
prüft aus Sicherheitsgründen, unter welchem Hostnamen es aufgerufen wird. Die Warnung erscheint,
wenn du die Domain wechselst. Bestätige den korrekten Hostnamen über den Button in der Meldung –
Matomo trägt ihn dann in config/config.ini.php ein.
Im Dashboard tauchen keine Besuche auf. Der Tracking-Code fehlt, ist falsch eingebaut, oder du
besuchst deine Seite selbst (Matomo ignoriert dich, wenn deine IP ausgeschlossen ist). Öffne deine
Website in einem privaten Fenster und prüfe im Netzwerk-Tab, ob ein Request an matomo.php
rausgeht. In Matomo hilft Verwaltung → Diagnose → Tracking Fehlschläge.
Das Dashboard lädt sehr langsam. Die On-the-fly-Archivierung rechnet bei jedem Aufruf. Richte den Archivierungs-Cron aus Schritt 8 ein und stelle die Berichterstellung auf Cron um.
Wartung & Backups
Updates sind bei Matomo unkritisch, aber regelmäßig fällig – etwa monatlich erscheint eine neue Version. Weil wir den Image-Tag auf 5.12 gepinnt haben, ziehst du Sicherheits-Patches innerhalb der 5.12-Reihe so:
cd /opt/matomo && docker compose pull && docker compose up -dBeim ersten Aufruf nach einem Update prüft Matomo, ob ein Datenbank-Upgrade nötig ist, und führt es nach einem Klick aus.
Vor einem Major-Upgrade: Backup und Release-Notes
compose.yaml an. Ein Major-Upgrade zieht oft umfangreichere Datenbank-Migrationen nach sich, die sich nicht ohne Weiteres zurückrollen lassen. Lies deshalb vorher die Release-Notes und ziehe unbedingt ein Backup (siehe unten), bevor du das neue Image startest.Backups umfassen zwei Dinge: die Datenbank (alle Besuchsdaten) und das app-Volume (deine Konfiguration in config/config.ini.php). Erstelle regelmäßig einen Datenbank-Dump …
docker compose exec -T db sh -c 'exec mariadb-dump -u matomo -p"$MARIADB_PASSWORD" matomo' > /opt/matomo/dump.sql… und nimm diesen Dump zusammen mit dem Ordner /opt/matomo in deine Restic-Off-Site-Backups auf. Ein netcup-Snapshot des ganzen Servers ist eine gute Ergänzung, aber kein Ersatz für ein echtes Off-Site-Backup – liegt beides beim selben Anbieter, sind bei einem Totalausfall auch beide weg.
Laufender Betrieb: Behalte den Speicherplatz im Auge – bei viel Traffic wächst die Datenbank. Die automatische Löschung alter Rohdaten (Schritt 7) und der Archivierungs-Cron (Schritt 8) halten Matomo dauerhaft schlank und schnell. Damit du merkst, wenn Matomo einmal nicht erreichbar ist, nimm die Instanz in dein Uptime-Kuma-Monitoring auf – ein einfacher HTTP-Check auf deine Statistik-Domain genügt.
Und der wichtigste Betriebs-Hinweis zum Schluss: Matomo lebt vom Datenschutz-Versprechen. Wer den Dienst einmal aufgesetzt hat, sollte die Anonymisierungs- und Lösch-Einstellungen aus Schritt 7 nicht wieder aufweichen – sie sind der Grund, warum du überhaupt ohne Consent-Banner auskommst. Prüfe nach jedem größeren Update kurz, dass sie noch stehen.
Zuletzt aktualisiert: 17.08.2026
Feedback per E-Mail: feedback@serverkueche.de
Das könnte dir auch schmecken

HitKeep: datenschutzfreundliche Web-Analytics selbst hosten
HitKeep mit Docker und Traefik aufsetzen: cookielose, DSGVO-freundliche Website-Statistik auf dem eigenen Server – mit …

Die eigene Website mit Hugo hosten – wie die Serverküche selbst
Statische Website mit Hugo bauen und im Docker-Container hinter Traefik ausliefern – schnell, sicher, ohne Datenbank. …

Immich optimieren: Handy-Backup, deutsche KI-Suche & Familien-Betrieb (Teil 2)
Immich Teil 2: Handy-Backup zuverlässig machen, die KI-Suche auf Deutsch umstellen, Bestandsfotos als externe Bibliothek …