Piwik – Basisinstallation

Zur gezielten Optimierung von Websites und insbesondere Webshops sind möglichst detaillierte Statistiken über die Besucher und Zugriffe erforderlich. Ein zur Erfassung und Auswertung von Webzugriffen häufig genutztes Analysewerkzeug ist das quelloffene Programm Piwik.
Piwik bietet im Vergleich zum Marktführer in diesem Bereich Google Analytics die Möglichkeit, die erfassten Daten auf dem eigenen Server zu speichern. Hierdurch kann der Betreiber die Einhaltung datenschutzrechtlicher Bestimmungen sicherstellen.
Wir befassen uns im nachfolgenden Beitrag mit den grundlegenden Schritten bei der Installation und Konfiguration eines Piwik-Servers für einen möglichst sicheren Betrieb. In einem Folgeartikel werden wir dann die Verknüpfung mit einer zu analysierenden Website und weitere Konfigurationsmöglichkeiten behandeln.

Voraussetzungen

Piwik ist eine webbasierte PHP-Anwendung, die Nutzer- und weitere Daten in einer MySQL– oder MariaDB-Datenbank ablegt. Grundlage für einen Piwik-Server ist daher häufig das Softwarepaket LAMP mit Linux, Apache, MySQL und PHP, das beispielsweise in dem Beitrag zur LAMP-Server-Installation beschrieben wird.
Unser Testsystem läuft unter Ubuntu Server 14.04 in der Domain test.local. Die Befehle führen wir mit Root-Rechten aus, z. B. nach Öffnen einer Rootshell mit sudo -i.

Basissystem installieren

Installation vorbereiten

Die wesentlichen serverseitigen Voraussetzungen für den Betrieb von piwik werden im Kapitel Piwik Requirements der ausführlichen Originaldokumentation aufgeführt. Neben dem vorhandenen LAMP-Server benötigen wir vier zusätzliche PHP-Module, die wir mit apt install installieren:

apt install php5-cli php5-curl php5-gd php5-geoip

Als weitere Vorbereitung legen wir eine eigene MySQL-Datenbank piwik und einen Datenbankbenutzer piwik mit passenden Rechten an:

mysql -p -u root
mysql> CREATE DATABASE piwik;
mysql> GRANT SELECT, INSERT, UPDATE, DELETE, CREATE, DROP, ALTER, CREATE TEMPORARY TABLES, LOCK TABLES ON piwik.* TO 'piwik'@'localhost' IDENTIFIED BY '***';

Piwik installieren

Nach den Vorbereitungsarbeiten laden wir den gepackten Quelltext piwik.zip der aktuellen Piwik-Version, zum Erscheinungsdatum dieses Artikels 2.16.1, vom Download-Server https://builds.piwik.org und entpacken ihn an geeigneter Stelle, in unserem Beispiel im Verzeichnis /usr/share/piwik. Danach löschen wir die überflüssige Datei How to install Piwik.html und setzen die Zugriffsrechte für die Ordner und Dateien. Hierbei erlauben wir sicherheitshalber nur dem Eigentümer root Vollzugriff auf das Piwik-Verzeichnis. Die Apache-Gruppe www-data erhält ausschließlich lesenden Zugriff. Die zugehörigen Anweisungen lauten:

mkdir -p /root/sources
wget -P /root/sources https://builds.piwik.org/piwik.zip
apt install unzip
unzip -o -u /root/sources/piwik.zip -d /usr/share
rm /usr/share/"How to install Piwik.html"
chown -R root:www-data /usr/share/piwik
find /usr/share/piwik \( -type d -exec chmod 0750 {} + \) -o \( -type f -exec chmod 0640 {} + \)

Die Zugriffsrechte und andere Sicherheitseinstellungen müssen später noch „aufgeweicht“ werden. Auf die Details werden wir an entsprechender Stelle eingehen.

Apache einrichten

Für unseren Piwik-Server richten wir eine eigene, ausschließlich per HTTPS erreichbare Subdomain piwik.test.local ein, die durch eine HTTP-Basisauthentifizierung geschützt ist. Weiterhin nutzen wir die Sicherheitsheader aus Webserver Apache absichern und setzen die in PHP absichern beschriebenen Sicherungsmaßnahmen um. Die Virtual-Host-Konfigurationsdatei für Apache erstellen wir in Anlehnung an die Konfiguration für PhpSecInfo im letztgenannten Beitrag. Zusätzliche Maßnahmen wie die Änderung des HTTPS-Port oder die Nutzung eines zufallsgenerierten Namens für die Subdomain sind Gegenstand eines Folgebeitrags.
Die Modifikationen der zentralen PHP-Konfigurationsdatei /etc/php5/apache2/php.ini sind hier der Vollständigkeit halber noch einmal aufgeführt:

...
upload_tmp_dir = /xxx/
open_basedir = /xxx/
file_uploads = Off
allow_url_fopen = Off
disable_functions = ${disable_functions}posix_setpgid,exec,ftp_login,mysql_pconnect,apache_setenv,popen,posix_getpwuid,posix_setsid,passthru,escapeshellcmd,ini_alter,ftp_raw,ftp_nb_fput,ini_restore,shell_exec,ftp_get,proc_get_status,highlight_file,proc_close,proc_terminate,syslog,ftp_connect,posix_uname,ini_get_all,proc_open,posix_kill,escapeshellarg,ftp_rawlist,posix_setuid,openlog,php_uname,system,ftp_exec,posix_mkfifo,proc_nice,ftp_put

Die komplette Apache-Konfigurationsdatei /etc/apache2/sites-available/piwik.conf lautet:

<VirtualHost *:443>
CustomLog ${APACHE_LOG_DIR}/access-piwik.log vhost_combined
DocumentRoot /usr/share/piwik
ErrorLog ${APACHE_LOG_DIR}/error-piwik.log
Header always set Content-Security-Policy "default-src 'self'; img-src 'self' data:; script-src 'unsafe-eval' 'unsafe-inline' 'self'; style-src 'unsafe-inline' 'self'"
Header always set Strict-Transport-Security "max-age=31536000"
Header always set X-Content-Type-Options "nosniff"
Header always set X-Frame-Options "SAMEORIGIN"
Header always set X-Xss-Protection "1; mode=block"
ServerAdmin webmaster@test.local
ServerName piwik.test.local
SSLCertificateFile /etc/ssl/certs/piwik.test.local.pem
SSLCertificateKeyFile /etc/ssl/private/piwik.test.local.key
SSLEngine on
<Directory /usr/share/piwik>
AuthBasicProvider file
AuthName "piwik"
AuthType Basic
AuthUserFile /etc/apache2/.htpasswd_piwik
php_admin_value open_basedir /usr/share/piwik/
Require valid-user
<Directory>
<VirtualHost>

Die Einträge für den Content-Security-Policy-Header wurden mit der Trial-and-Error-Methode mit dem Firefox-Add-on Firebug bestimmt.
Nach der Aktivierung der Piwik-Konfiguration und dem Neustart von Apache mit

a2ensite piwik.conf
service apache2 restart

und eventuell erforderlichen Anpassungen an dem / den DNS-Server/n können wir Piwik konfigurieren.

Piwik konfigurieren

Basiskonfiguration

Die grundlegenden Einstellungen von Piwik werden beim erstmaligen Aufruf im Browser mit

https://piwik.test.local/

in mehreren aufeinanderfolgenden Schritten festgelegt.
Den ersten Konfigurationsversuch quittiert die Piwik-Benutzeroberfläche mit der Fehlermeldung

An error occurred
The directory "/usr/share/piwik/tmp/cache/tracker/" does not exist and could not be created.

Ursache sind fehlende Schreibrechte der Gruppe www-data für den Ordner für temporäre Dateien /usr/share/piwik/tmp/, die wir folgendermaßen aktivieren:

chmod 0770 /usr/share/piwik/tmp

Beim erneuten Aufruf von https://piwik.test.local/ meldet Piwik beim zweiten Schritt, der Systemprüfung, dass ein Schreibzugriff auf das Verzeichnis /usr/share/piwik/config, in dem die Konfigurationsdatei config.ini.php abgelegt wird, nicht möglich ist. Zusätzlich werden noch zwei Warnungen ausgegeben:

Tracker-Status 500 GET-Request zu piwik.php fehlgeschlagen.
shell_exec Sie müssen diese eingebaute Funktion aktivieren.

Um den Schreibzugriff zu ermöglichen, ändern wir die Rechte analog zum Verzeichnis tmp:

chmod 0770 /usr/share/piwik/config

Wie ein Blick in die Apache-Logdatei /var/log/apache2/error-piwik.log zeigt, ist der Grund für die Warnmeldung zum Tracker-Status die noch nicht existierende Konfigurationsdatei:

... PHP Fatal error:  Uncaught exception 'Exception' with message 'The configuration file {/usr/share/piwik/config/config.ini.php} has not been found or could not be read.' ...

Da config.ini.php erst nach dem kompletten Durchlauf der Konfigurationsschritte angelegt wird, können wir diese, allerdings unkritische Warnmeldung nicht verhindern.
Die PHP-Funktion shell_exec zu aktivieren, deren Nutzung wir zuvor mit der disable_functions-Anweisung in php.ini unterbunden haben, ist aus Sicherheitsgründen nicht ratsam. Während der Tests für diesen Beitrag waren trotz deaktivierter shell_exec-Funktion keine Fehler oder sonstigen Auffälligkeiten bei Piwik festzustellen.
Beim dritten Anlauf kann die Basiskonfiguration vollständig durchgeführt werden. Auf der Seite Datenbank einrichten geben wir den Datenbanknamen piwik sowie den zugehörigen Benutzer piwik nebst Passwort ein. Für den Hauptadministrator super setzen wir ebenfalls ein Passwort und hinterlegen eine E-Mail-Adresse, z. B. piwik@test.local. Die Felder auf der Seite Website hinzufügen füllen wir mit den Daten der zu analysierenden Website, hier https://www.test.local:

Name der Website test
URL der Website https://www.test.local
Zeitzone der Website Berlin
Ecommerce Dies ist keine Ecommerce Seite

Für alle anderen Einstellungen können wir die Default-Werte übernehmen. Nachdem die Einrichtungsschritte erfolgreich abgearbeitet sind, erscheint der Piwik-Anmeldebildschirm für den Benutzer super.
Zum Abschluss schützen wir noch die Piwik-Konfiguration vor Überschreiben:

chmod 0750 /usr/share/piwik/config
chown root:www-data /usr/share/piwik/config/config.ini.php
chmod 0640 /usr/share/piwik/config/config.ini.php

Piwik anpassen

Die bereits bei der Erstinstallation durchlaufene Systemprüfung ist ein guter Ausgangspunkt für die weiteren Anpassungsarbeiten. Ein Aufruf mit

https://piwik.test.local/index.php?module=Installation&action=systemCheckPage

liefert neben der schon bekannten Warnmeldung zu shell_exec zwei Kommentare zum MySQL-Befehl LOAD DATA INFILE und zur Standorterkennung:

... Die Benutzung von LOAD DATA INFILE erhöht die Geschwindigkeit des Piwik Archivierungsprozesses erheblich. ...
... Standorterkennung funktioniert, aber Sie nutzen keinen der empfohlenen Anbieter. ...

LOAD DATA INFILE ermöglichen

Mit der LOAD DATA INFILE-Funktion werden temporäre CSV-Dateien aus dem Verzeichnis /usr/share/piwik/tmp/assets in die Datenbank eingelesen. Damit die Funktion genutzt werden kann, erhält der Datenbankbenutzer piwik mit der GRANT FILE-Anweisung Lese- und Schreibrechte für alle Dateien im Zugriffsbereich des MySQL-Servers:

mysql -p -u root
mysql> GRANT FILE ON *.* TO 'piwik'@'localhost';

Die temporären CSV-Dateien legt Piwik bereits mit Vollzugriff für alle an, also auch für den Benutzer mysql, mit dessen Rechten der MySQL-Server läuft. Darüber hinaus muss für die übergeordneten Ordner bis hin zum Installationsverzeichnis das Ausführen-Recht gesetzt sein, das einen Verzeichniswechsel ermöglicht. Da wir keine zusätzlichen separaten Rechte für den Nutzer mysql einrichten können, erlauben wir allen Benutzern das Ausführen auf Verzeichnisebene:

chmod 0751 /usr/share/piwik
chmod 0771 /usr/share/piwik/tmp
chmod 0751 /usr/share/piwik/tmp/assets

Falls wie auf unserem Testsystem die Sicherheitssoftware AppArmor läuft, kann der Dateizugriff für MySQL zusätzlich eingeschränkt sein. Zeigt die Statusabfrage

aa-status

den mysqld-Prozess in der Liste der überwachten Anwendungen unter … processes are in enforce mode an, müssen die hinterlegten AppArmor-Regeln geändert werden. Hierzu ergänzen wir die Konfigurationsdatei /etc/apparmor.d/usr.sbin.mysqld um eine Zeile, die mysqld den Lesezugriff auf die Dateien im Unterverzeichnis assets erlaubt:

...
/usr/sbin/mysqld {
...
/usr/share/piwik/tmp/assets/* r,
...

Zur Übernahme der Änderung starten wir AppArmor neu:

service apparmor restart

In How do I get LOAD DATA INFILE to work on my server? wird vorgeschlagen, auch die Option local-infile in der MySQL-Konfigurationsdatei /etc/mysql/my.cnf zu setzen. Dies ist in unserem Fall nicht erforderlich, da Piwik den damit möglichen alternativen Aufruf LOAD DATA LOCAL INFILE bei funktionierendem Dateizugriff mit LOAD DATA INFILE nicht verwendet.

Standorterkennung verbessern

Zur Standorterkennung empfiehlt Piwik die Nutzung der GeoIP-Datenbank mit Hilfe des PECL-Moduls geoip. Die erforderliche PHP-Erweiterung php5-geoip haben wir bereits im Rahmen der Installationsvorbereitungen installiert.
Das geoip-Modul liest die Zuordnung von IP-Adressen zu geografischen Orten aus einer Datei mit dem Namen GeoIPCity.dat. Der Ablageort dieser Datei, hier beispielsweise das Verzeichnis /usr/share/piwik/misc, wird im Parameter geoip.custom_directory in der PHP-Konfigurationsdatei /etc/php5/apache2/php.ini übergeben:

geoip.custom_directory=/usr/share/piwik/misc

Nach dem Neustart von Apache mit

service apache2 restart

steht die geänderte Konfiguration zur Verfügung.
Piwik unterstützt unter anderem die kostenfreie GeoIP-Datenbank GeoLite City von MaxMind, die wir wie folgt herunterladen, entpacken und mit passenden Zugriffsrechten als Datei /usr/share/piwik/misc/GeoIPCity.dat speichern können:

wget -P /root/sources https://geolite.maxmind.com/download/geoip/database/GeoLiteCity.dat.gz
gunzip /root/sources/GeoLiteCity.dat.gz
mv /root/sources/GeoLiteCity.dat /usr/share/piwik/misc/GeoIPCity.dat
chown root:www-data /usr/share/piwik/misc/GeoIPCity.dat
chmod 0640 /usr/share/piwik/misc/GeoIPCity.dat

Auf der Piwik-Konfigurationsseite für die Standorterkennung

https://piwik.test.local/index.php?module=UserCountry&action=adminIndex

stellen wir schließlich noch GeoIP (PECL) ein. Die auf derselben Seite angebotene automatische Aktualisierung für GeoIP-Datenbanken nutzen wir nicht. Stattdessen kann man bei Bedarf die Befehle zur Installation von GeoIPCity.dat in einem Shellskript zusammenfassen und in regelmäßigen zeitlichen Abständen per Cron-Job aufrufen.
Weitere Details zur Standorterkennung mit GeoIP-Datenbanken können dem Abschnitt Geo Locate your visitors und den FAQs How do I install the GeoIP Geo location PECL extension? und How do I get the GeoIP databases to improve accuracy of Country detection, and detect visitors’ Cities and Regions? der Piwik-Dokumentation entnommen werden.

Piwik absichern

Die von den Entwicklern als sinnvoll erachteten Sicherheitsmaßnahmen sind in der Anleitung How to configure Piwik for security zusammengefasst, auf die wir nachfolgend auszugsweise eingehen.
Die Empfehlungen, Piwik in einer separaten MySQL-Datenbank mit einem eigenen Datenbankbenutzer und Passwort zu installieren sowie auschließlich Verbindungen per HTTPS zuzulassen, haben wir umgesetzt. Die Einrichtung einer automatischen Umleitung von HTTP auf HTTPS in der Piwik-Konfiguration ist nicht erforderlich, da die Website nicht per HTTP erreichbar ist. Der Zugriff auf Piwik ist durch eine HTTP-Basisauthentifizierung geschützt. Mit den Ausnahmeregelungen für die Dateien piwik.php und piwik.js und den URL index.php?module=CoreAdminHome&action=optOut werden wir uns in einem Folgeartikel befassen.
Die Sicherung der Konfigurationsdatei config.ini.php und der Piwik-Datenbank kann im Rahmen eines Systembackups mit einem der gängigen Datensicherungsprogramme/-verfahren erfolgen. Einen Überblick gibt z. B. der Wiki-Beitrag zur Ubuntu-Datensicherung.
Um die Datenbank in einem konsistenten Zustand zu speichern, erzeugen wir vor dem eigentlichen Systembackup mit dem Programm mysqldump eine lokale Backupdatei piwik.sql. Diese Datei sollte außerhalb des durch Apache lesbaren Piwik-Ordners abgelegt werden. In unserem Beispiel nutzen wir das Homeverzeichnis des Benutzers theo:

mysqldump --opt --password --user=piwik piwik > /home/theo/piwik.sql

Es bietet sich an, die lokale Datenbanksicherung mit einem Cron-Job zu automatisieren und beispielsweise täglich auszuführen.
Zur Absicherung der PHP-Umgebung empfehlen die Entwickler das SecurityInfo-Plugin, das wie die anderen Piwik-Plugins im Unterordner plugins des Installationsverzeichnisses abgelegt wird. Damit neue Plugins über die Piwik-Benutzeroberfläche installiert werden können, müssen dieser Ordner und zusätzlich die Konfigurationsdatei config.ini.php zum Schreiben für www-data freigegeben werden:

chmod 0770 /usr/share/piwik/plugins
chown www-data:www-data /usr/share/piwik/config/config.ini.php

Das Plugin können wir dann über den Marketplace

https://piwik.test.local/index.php?module=CorePluginsAdmin&action=marketplace

installieren und aktivieren.
Nach der Installation stellt man die Rechte mit

chmod 0750 /usr/share/piwik/plugins
chown -R root:www-data /usr/share/piwik/plugins/SecurityInfo
find /usr/share/piwik/plugins/SecurityInfo \( -type d -exec chmod 0750 {} + \) -o \( -type f -exec chmod 0640 {} + \)
chown root:www-data /usr/share/piwik/config/config.ini.php

wieder auf sicherere Werte ein.
Ein Aufruf von SecurityInfo mit

https://piwik.test.local/index.php?module=SecurityInfo&action=index

liefert folgende Meldungen:

... WARNING: /usr/share/piwik/plugins/SecurityInfo/PhpSecInfo/Test/CGI/force_redirect.php(89): Warning - ini_get_all() has been disabled for security reasons ...
.. PHP You are running PHP 5.5.9-1ubuntu4.17. The latest version of PHP is 5.6.24. ...
... upload_tmp_dir unable to retrieve file permissions on upload_tmp_dir ...

Die erste Warnung scheint ein Fehler im SecurityInfo-Plugin zu sein. Die PHP-Version 5.5.9 ist Bestandteil des LAMP-Servers unter Ubuntu 14.04 und ließe sich durch eine manuelle Installation auf einen aktuelleren Stand bringen. Auf upload_tmp_dir kann Piwik nicht zugreifen, da wir gemäß dem Beitrag PHP absichern für diesen Ordner einen nicht-existierenden Namen /xxx/ gewählt haben.
Ein vergleichender Aufruf des SecurityInfo zugrunde liegenden Analyseprogramms PhpSecInfo meldet auf dem Testsystem einen 100%-Erfolg, wobei auch die genutzte PHP-Version nicht als kritisch eingestuft wird. Wir können daher an dieser Stelle von einem möglichst sicher eingerichteten Piwik-Server ausgehen.

Piwik-Update

Sobald ein Programmupdate bereitsteht, erscheint auf der Benutzeroberfläche ein entsprechender Vermerk mit einem Link zu Piwiks Ein-Klick-Aktualisierung. Für diese Aktualisierung benötigt der Apache-Prozess Schreibrechte für das Piwik-Verzeichnis, die wir z. B. wie folgt setzen können:

chown -R www-data:www-data /usr/share/piwik

Nach dem Update der Programmdateien und der Aktualisierung der Datenbank über die Piwik-Oberfläche richten wir die ursprünglichen Berechtigungen wieder ein:

chown -R root:www-data /usr/share/piwik
find /usr/share/piwik \( -type d -exec chmod 0750 {} + \) -o \( -type f -exec chmod 0640 {} + \)
chown -R www-data:www-data /usr/share/piwik/tmp/*
find /usr/share/piwik/tmp/* -type f -exec chmod 0644 {} +
chmod 0751 /usr/share/piwik
chmod 0771 /usr/share/piwik/tmp
chmod 0751 /usr/share/piwik/tmp/assets
find /usr/share/piwik/tmp/sessions/* -type f -exec chmod 600 {} +
find /usr/share/piwik/tmp/templates_c/* -type d -exec chmod 0755 {} +

Signalisiert die Piwik-Benutzeroberfläche eine Updatemöglichkeit für ein Plugin wie beispielsweise SecurityInfo, lauten die Aufrufe zum Setzen der Berechtigungen vor dem Update

chown www-data:www-data /usr/share/piwik/plugins
chown -R www-data:www-data /usr/share/piwik/plugins/SecurityInfo

und nach dem Update

chown root:www-data /usr/share/piwik/plugins
chown -R root:www-data /usr/share/piwik/plugins/SecurityInfo
find /usr/share/piwik/plugins/SecurityInfo \( -type d -exec chmod 0750 {} + \) -o \( -type f -exec chmod 0640 {} + \)