Ubuntu 18.04 Server mit Nginx, MySQL, PHP und SSL aufsetzen

Inhaltsverzeichnis

Ein eigenständiger Webserver ermöglicht es Websites schneller auszuliefern, eigene Software zu installieren und alle Einstellungen selbst zu treffen. Dabei ist man nicht auf die Vorgaben eines Hosters beschränkt, im Gegenzug muss man sich aber selbst um die Konfiguration und Absicherung des Servers kümmern. Diese Anleitung kann auf vServer, Root Server oder Droplets angewandt werden. So gut wie alle Hoster bieten diverse Linux Distributionen an, die automatisch auf dem jeweiligen Server installiert werden können. Die einzige Vorgabe die für die Durchführung dieser Anleitung erfüllt werden muss, ist der Einsatz von Ubuntu in der Version 18.04. Neben dem Server selbst benötigen wir natürlich auch Zugang zu dem Server per SSH und einem Root User. Diese Informationen sollten euch nach der Einrichtung über die Weboberfläche des Hosters zur Verfügung gestellt werden. Haben wir alle benötigten Informationen können wir direkt loslegen. Sollte euer Hoster euch die Möglichkeit geben SSH Keys für die Anmeldung zu benutzen solltet Ihr diese Option unbedingt nutzen. Die Vorgehensweise für die Anmeldung ist in diesem Fall bei jedem Hoster leicht unterschiedlich und wird in den meisten Fällen vom Hoster direkt beschrieben.

In dieser Anleitung arbeite ich mit einem Server der bei DigitalOcean gehostet wird. Interessierte können sich über diesen Link einen Account erstellen (Affiliate Link). Wenn Ihr euch über den Link registriert erhaltet Ihr 100 US-Dollar an Guthaben das Ihr über einen Zeitraum von 60 Tagen verbrauchen könnt. Nach den 60 Tagen verfällt das Guthaben und alle damit verbundenen Services. Wenn Ihr mit dem Service zufrieden seid könnt Ihr euch zusätzliches Guthaben kaufen. Sobald Ihr mehr als 25 US-Dollar aufladet erhalte Ich für das Referral 25 US-Dollar auf mein Konto gutgeschrieben. Für euch ergeben sich dadurch keine höheren Preise oder andere Nachteile. Natürlich könnt Ihr auch andere Hoster wie z.B. Hetzner nutzen, die Entscheidung liegt bei euch.

Sind Sie nicht mehr zufrieden mit Ihrer Website? Kämpfen Sie mit langen Ladezeiten auf Ihrer Website oder Ihrem Webshop oder benötigen Sie einen zeitgemäßen Online Auftritt? Ich biete Website ErstellungSuchmaschinenoptimierung sowie WordPress Plugin Entwicklung in Wien und Niederösterreich.

Grundlegendes Server Setup

Anmeldung

Sobald unser Server aufgesetzt wurde und wir die benötigten Anmeldeinformationen bzw. SSH Keys haben können wir loslegen. Für die Fernwartung nutzen wir SSH. Linux und Mac User können direkt über das Terminal eine Verbindung aufbauen. Windows Nutzer können auf Tools wie Putty oder MobaXterm zurückgreifen. Der Vorteil von MobaXterm ist, dass man Profile für die jeweiligen Server einfacher verwalten kann. Ich verwende MobaXterm für die Verwaltung, die Screenshots in dieser Anleitung stammen also direkt daraus.

Wir starten die Verbindung zu unserem Server (per Terminal) über den folgenden Befehl (solltet Ihr SSH Keys nutzen müsst Ihr den Pfad zu den Keys zusätzlich angeben). Je nach verwendeter Software gibt es andere Schritte die man für die Anmeldung durchgehen muss. Sollte euer Hoster die jeweiligen Optionen nicht beschreiben könnt Ihr auch direkt Google für die Vorgehensweise in eurem Fall befragen.

				
					ssh root@ip_des_servers
				
			

Solltet Ihr euch per Passwort mit dem Server verbinden werdet Ihr eventuell aufgefordert euer Passwort zu ändern. Folgt dabei einfach den Schritten die euch am Schirm angezeigt werden. Legt euch auch direkt z.B. eine Excel Liste zu in der Ihr die wichtigsten Kennwörter speichert.

Nach der erfolgreichen Anmeldung sollte eure SSH Sitzung in etwa folgendes anzeigen.

Firewall

Nach erfolgreicher Anmeldung starten wir direkt mit der ersten Konfiguration unserer Firewall. Ubuntu wird mit einer passenden Lösung Namens UFW ausgeliefert. Die in dieser Anleitung genutzten Apps registrieren jeweils eigene Profile die für die einfache Verwendung in Verbindung mit UFW genutzt werden können.

Um zu sehen welche Apps gerade installiert sind und per UFW direkt gesteuert werden können geben wir den folgenden Befehl ein:

				
					ufw app list
				
			

Das Kommentar sollte uns den folgenden Output liefern:

				
					Available applications:
  OpenSSH
				
			

OpenSSH ist derzeit die einzige Anwendung am Server die per UFW konfiguriert werden kann. Unsere Firewall ist derzeit noch nicht aktiviert. Bevor wir die Firewall aktivieren können müssen wir aber OpenSSH freigeben um uns nicht selbst auszusperren. Die Freigabe erfolgt mithilfe von „ufw allow AppName“. Für OpenSSH sieht der Befehl also wie folgt aus:

				
					ufw allow OpenSSH
				
			

Der Output sollte wie folgt aussehen:

				
					Rules updated
Rules updated (v6)
				
			

Unsere Regeln wurden also erfolgreich aktualisiert, Zeit die Firewall zu aktivieren. Dazu geben wir den folgenden Befehl ein.

				
					ufw enable
				
			

Bevor die Firewall aktiviert wird, erfolgt noch eine Sicherheitsabfrage die Ihr per „y“ bestätigen müsst. Anschließend sollte euch der folgende Output gezeigt werden.

				
					Firewall is active and enabled on system startup
				
			

Perfekt, nun werfen wir noch schnell einen Blick auf den aktuellen Status unserer Firewall mithilfe von:

				
					ufw status
				
			

Hier werden uns jetzt die registrierten Apps mit den jeweiligen Firewall-Einstellungen angezeigt. Die Liste ist in unserem Fall recht kurz. Solltet Ihr bereits weitere Software installiert haben, könnte die Liste etwas länger ausfallen.

Nachfolgend ein Bild das die letzten Eingaben zeigt.

User Account erstellen

In Linux Systemen ist der Root User der uneingeschränkte Administrator des Systems. Damit hat das Konto Zugriff auf alle Aspekte des Systems und kann diese somit auch bewusst oder unbewusst negativ beeinflussen. Direkt nach der erfolgreichen Anmeldung erstellen wir aus diesem Grund einen neuen User den wir unserer Root Benutzergruppe hinzufügen, dadurch aber nicht alle Rechte erhält die dem eigentlichen Root User zugesprochen werden.

Um einen neuen Nutzer anzulegen geben wir den folgenden Befehl ein. In unserem Fall bennenen wir den User „osulzer“.

				
					adduser osulzer
				
			

Wir bestätigen die Eingabe mit Enter und werden direkt nach einem Passwort gefragt. Nutzt ein starkes Passwort. Solltet Ihr noch keinen Passwort Manager nutzen ist jetzt vielleicht ein guter Zeitpunkt damit zu beginnen. Alternativ könnt Ihr ein eigenes Passwort erstellen und dieses an einem sicheren Ort abspeichern. Nach dem Passwort werdet Ihr über weitere Details zu dem User gefragt, Ihr könnt hier entweder mehr Informationen angeben oder einfach per Enter-Taste weiterspringen.

Jetzt fügen wir den neuen User der Root-Gruppe hinzu. Anschließend kann unser User „sudo“ Befehle ausführen.

				
					usermod -aG sudo osulzer
				
			

Der Output eurer SSH Session sollte jetzt in etwa wie folgt aussehen.

SSH Zugang für neuen Benutzer erstellen

Für anfallende Arbeiten auf unserem Server verwenden wir in Zukunft unseren neuen Benutzer. Damit wir den Nutzer direkt für das Login auf unserem Server nutzen können müssen aber noch ein paar Einstellungen getroffen werden. Solltet Ihr euch ausschließlich per Usernamen und Passwort am Server Anmelden reicht es die Verbindung per „ssh osulzer@ip_des_servers“ im Terminal einzugeben und sich zu verbinden. Die sichere Methode per SSH Keys erfordert weitere Vorkehrungen.

Achtung: Bleibt aus Sicherheitsgründen mit dem Root User vorerst auf eurem Server angemeldet. Schließt das Fenster also nicht bis das neue Login getestet wurde und funktioniert.

SSH Key Authentizierung aktivieren

In Zukunft möchten wir uns nur noch mit unserem neu erstellten User anmelden. Dafür müssen wir die SSH Keys die derzeit root zugewiesen sind, für unseren neuen User konfigurieren. Wir nutzen dafür rsync um die Zugriffsrechte beim kopieren der Keys zu behalten. Bleibt bitte mit eurer root SSH Session angemeldet, sollte es nämlich beim kopieren der Keys zu einem Fehler gekommen sein, könntet Ihr euch aus dem Server aussperren. Zum kopieren nutzen wir den folgenden Befehl, in eurem Fall müsst Ihr die Stellen an denen ich „osulzer“ eintrage den von euch gewählten Usernamen auswählen. Bevor der Eingabe hier noch eine kurze Klarstellung. Der Teil des Befehls “chown=osulzer:osulzer“ bedeutet nicht „Username:Kennwort“ sondern „Username:Usergruppe“. In unserem Fall müsst Ihr also zweimal den Usernamen getrennt mit „:“ eingeben. Achtet auch darauf, dass der Teil „~/.ssh“ keinen Slash am Schluss hat, sonst wird statt dem Ordner der Inhalt des Ordners kopiert.

				
					rsync --archive --chown=osulzer:osulzer ~/.ssh /home/osulzer
				
			

Nach der Ausführung des Befehls sollte es möglich sein, dass Ihr euch mit eurem neuen Nutzer per SSH anmeldet. Anders als beim bislang verwendeten root user müsst Ihr mit eurem neuen User für die Ausführung von Befehlen die Änderungen am System vornehmen den Zusatz „sudo“ am Anfang des Befehls eingeben. Der Befehl fragt anschließend das Kennwort ab welches Ihr bei der Erstellung des Nutzers eingeben habt.

Ab sofort arbeiten wir nur noch über diesen User, schließt also eure root Session mit dem Server und macht mit der neuen SSH Session auf dem Ihr mit dem von euch erstellten User angemeldet seit weiter.

Für die Konfiguration von Nginx und SSL benötigen wir eine Domain die auf unseren Server zeigt. Je nachdem wo Ihr eure Domains registriert habt, gibt es unterschiedliche Einstellungen und Oberflächen um die DNS-Einstellungen der Domain zu ändern. Wichtig ist, dass der „A“-Eintrag der Domain auf die IP-Adresse es Servers zeigt. Nachfolgend eine Kurzerklärung für die Einträge.

NameTypInhalt
*.euredomain.comAserver_ip_adresse
www.euredomain.comAserver_ip_adresse
euredomain.comAserver_ip_adresse

Die Änderung dieser Einstellungen kann ein paar Stunden dauern. In der Zwischenzeit könnt Ihr mit der Installation von Nginx fortfahren bis wir zum Punkt mit der Konfiguration des Server Blocks für die Domain kommen. Ab diesem Zeitpunkt sollte eure Domain im besten Fall bereits auf euren neuen Server zeigen.

Kurzer Tipp:

Ihr könnt den DNS-Cache auf eurem Rechner zurücksetzen um schneller die aktualisierten Adressen zu erhalten.

Windows User

Startet eine Eingabeaufforderung und gebt den folgenden Befehl ein:

				
					ipconfig /flushdns
				
			

Mac OSX

				
					sudo dscacheutil -flushcache
				
			

Linux User

				
					sudo /etc/init.d/nscd restart

				
			

Nginx Installation

Wer bislang nur mit normalen Webspace zu tun gehabt hat, wird vielleicht nicht direkt wissen um was es sich bei Nginx handelt. Nginx bietet eine bessere Performance und spart im Vergleich zu Apache wichtige Server Ressourcen. Nachteile im Vergleich zu Apache sind z.B. der größere Aufwand um zusätzliche Module zu installieren und die fehlende Möglichkeit z.B. Servervariablen in einer .htaccess Datei zu ändern. Welche Lösung Ihr schlussendlich für euren Server nutzt bleibt euch überlassen, in diesem Tutorial bearbeiten wir Nginx.

Bevor wir mit der Installation von Nginx beginnen aktualisieren wir unseren lokalen Paketindex. Dafür geben wir den folgenden Befehl ein.

				
					sudo apt update
				
			

Sollten euch an dieser Stelle angezeigt werden das Updates verfügbar sind, könnt Ihr diese über den folgenden Befehl installieren.

				
					sudo apt upgrade

				
			

Jetzt aktualisieren wir Nginx direkt über das Ubuntu Repository

				
					sudo apt install nginx
				
			

Kurz nach der Ausführung des Befehls fragt euch das System ob Ihr die neuen Dateien herunterladen wollt. Bestätigt den Befehlt mittels „y“

Ubuntu startet Nginx direkt nach der Installation, wir müssen den Dienst also nicht separat registrieren. Bevor wir Anfragen per HTTP testen können müssen wir Nginx aber noch in unserer Firewall freigeben. Werfen wir dazu zuerst einen Blick auf die durch Nginx registrierten Profile in der UFW Firewall.

				
					sudo ufw app list
				
			

Output:

				
					Available applications:
  Nginx Full
  Nginx HTTP
  Nginx HTTPS
  OpenSSH
				
			

Nginx hat uns gleich mehrere Profile zur Verfügung gestellt. Wir können auf Wunsch Anfragen die über HTTP kommen blockieren und nur HTTPS Anfragen zulassen. Da wir HTTP Requests später zu HTTPS weiterleiten und deswegen die Anfragen nicht direkt blockieren wollen wählen wir das Profil „Nginx Full“ zur Freigabe. Dazu geben wir den folgenden Befehl ein.

				
					sudo ufw allow 'Nginx Full'
				
			

Output:

				
					Rule added
Rule added (v6)
				
			

Nun sollte der Server auf HTTP Anfragen reagieren. Startet den Browser eures Vertrauens und navigiert zur IP-Adresse oder der Domain die auf die IP Adresse des Servers zeigt. Hat alles geklappt sollte euch die folgende Nachricht angezeigt werden.

Gratulation, Nginx läuft, wir sind aber noch nicht fertig. Anders als bei Apache müssen wir bei der Benutzung von Nginx PHP selbst installieren. Wir verwenden dazu php-fpm was für „fastCGI process manager“ steht. Nginx leitet PHP Anfragen an diese Software weiter um PHP Code auszuführen. Neben php-fpm installieren wir an dieser Stelle auch gleich die passende Schnittstelle um später auch die Möglichkeit zu haben über PHP auf unsere MySQL Datenbank zugreifen zu können. Als diese Anleitung erstellt wurde, installiert der folgende Befehl PHP in der Version 7.2.

				
					sudo apt install php-fpm php-mysql
				
			

Jetzt sind die benötigten Packages installiert, wir müssen Nginx aber noch klarmachen, dass diese packages genutzt werden sollen. Nginx nutzt sogenannte Server Blocks die es euch ermöglichen z.B. mehrere Websites auf einem Server laufen zu lassen. Die jeweiligen Websites können dabei voneinander getrennte Konfigurationen nutzen. Nginx zeigt nach der Installation auf das Verzeichnis „/var/www/html“, zum jetzigen Zeitpunkt zeigt der Server also direkt auf den Inhalt des Ordners. Für unsere Domain erstellen wir ein eigenes Verzeichnis mit der passenden Ordnerstruktur. Der folgende Befehl erledigt das für uns mithilfe des -p Parameters.

				
					sudo mkdir -p /var/www/euredomain.com/html
				
			

Anschließend übergeben wir die Inhaberschaft an die $USER Umgebungsvariable.

				
					sudo chown -R $USER:$USER /var/www/euredomain.com/html

				
			

Nun setzen wir noch die Zugriffsrechte

				
					sudo chmod -R 755 /var/www/euredomain.com

				
			

Den erstellten Ordner unter /var/www/euredomain.com/html nutzen wir als Ausgangspunkt für unsere Website. Bevor das klappt müssen wir Nginx aber noch konfigurieren. Dazu erstellen wir einen neuen Serverblock unter /etc/nginx/sites-available/.

				
					sudo nano /etc/nginx/sites-available/euredomain.com

				
			

Fügt jetzt den folgenden Code als Start-Konfiguration ein.

				
					server {
	listen 80;
	listen [::]:80;

	root /var/www/euredomain.com/html;
	index index.php index.html index.htm index.nginx-debian.html;

	server_name euredomain.com www.euredomain.com;

	location / {
		try_files $uri $uri/ =404;
	}

	location ~ \.php$ {
		include snippets/fastcgi-php.conf;
		fastcgi_pass unix:/var/run/php/php7.2-fpm.sock;
	}

	location ~ /\.ht {
		deny all;
	}
}
				
			

Wir nutzen den Nano Editor dieser speichert eure Eingabe mit „STRG+O –> Enter“ und schließt das Fenster anschließend mit STRG+X.

Was machen wir hier genau?

listen – Unser Serverblock lauscht auf Port 80 nach Anfragen und zeigt anschließend den Inhalt des Verzeichnisses /var/www/euredomain.com/html.

root – Anschließend geben wir an in welchem Ordner Nginx nach Dateien suchen soll und welche Dateien als index zugelassen werden.

server – Hier geben wir an, dass der Block sich auf Anfragen die per http://www.euredomain.com sowie http://euredomain.com eintrudeln bezieht.

location / gibt an, dass wir eine 404-Fehlerseite ausgeben wenn keine index Datei gefunden wurde. „

location ~ \.php$ – verweist auf das Programm das sich um die Interpretation von PHP kümmert. In unserem Fall wird die php7.2-fpm.sock eingebunden.

location ~ /\.ht – Nginx unterstützt keine .htaccess Dateien und würde diese direkt in Klartext ausgeben. Mit dieser Einstellung verhindern wir die Ausgabe an Besucher.

Um unseren neuen Server Block beim nächsten Start von Nginx auszuführen müssen wir einen symlink zur neuen konfiguration erstellten.

				
					sudo ln -s /etc/nginx/sites-available/euredomain.com /etc/nginx/sites-enabled/
				
			

Solltet Ihr Domains mit langen Namen nutzen, solltet Ihr noch die folgende Einstellung von Nginx aktivieren. Gebt dafür den folgenden Befehl ein:

				
					sudo nano /etc/nginx/nginx.conf

				
			

In der Datei suchen wir den Punkt „server_names_hash_bucket_size“ und entfernen das #-Symbol davor. Speichert die Datei und schließt den Editor.

Bevor wir Nginx neu starten testen wir die neue Konfiguration.

				
					sudo nginx -t

				
			

Hat alles funktioniert sollte der Output wie folgt aussehen.

Nun starten wir Nginx neu um die neuen Einstellungen zu aktivieren

				
					sudo systemctl restart nginx

				
			

Ein Besuch eurer Domain sollte euch jetzt eine 404 Fehlerseite zeigen. Keine Panik, die Fehlermeldung ist korrekt, wir haben ja noch keine Dateien in unserem Public Verzeichnis. Das lässt sich schnell ändern. Wir erstellen einfach eine index.php Datei.

				
					nano /var/www/euredomain.com/html/index.php

				
			

In die Datei fügen wir folgendes ein und speichern.

				
					<?php
phpinfo();
				
			

Unser Server sollte jetzt Details zur genutzten PHP Version ausgeben. Das bedeutet, dass PHP erfolgreich ausgeführt wird.

Die wir diese Informationen nicht öffentlich zugänglich machen sollten, löschen wir die index.php Datei jetzt wieder.

				
					rm /var/www/euredomain.com/html/index.php

				
			

Nginx DSGVO Konform machen

IP Adressen anonymisieren (problematisch)

Standardmäßig speichert Nginx jede Anfrage an den Server in der access.log Datei ab. Dabei wird auch die IP-Adresse des Besuchers gespeichert. Da IP-Adressen als personenbezogene Daten gelten, haben wir die Möglichkeit die IP Adresse zu anonymisieren. Dazu nutzen wir ein kleines Script das ein findiger StackOverflow Nutzer geschrieben hat. Das Problem an der folgenden Änderung: Auch Angreifer werden durch diese Methode anonymisiert und sind somit nicht mehr nachverfolgbar. Ich empfehle die Speicherdauer der Logfiles auf 7 Tage zu minimieren (nächster Punkt) und dazu passend im Datenschutzhinweis auf die Dauer der Speicherung der Daten hinzuweisen.

				
					sudo nano /etc/nginx/nginx.conf

				
			

Direkt nach „http {„ fügen wir den folgenden Code ein.

				
					map $remote_addr $ip_anonym1 {
    default 0.0.0;
    "~(?P<ip>(\d+)\.(\d+)\.(\d+))\.\d+" $ip;
    "~(?P<ip>[^:]+:[^:]+):" $ip;
}

map $remote_addr $ip_anonym2 {
    default .0;
    "~(?P<ip>(\d+)\.(\d+)\.(\d+))\.\d+" .0;
    "~(?P<ip>[^:]+:[^:]+):" ::;
}

map $ip_anonym1$ip_anonym2 $ip_anonymized {
    default 0.0.0.0;
    "~(?P<ip>.*)" $ip;
}

log_format anonymized '$ip_anonymized - $remote_user [$time_local] '
'"$request" $status $body_bytes_sent '
'"$http_referer" "$http_user_agent"';
				
			

Unter „Logging Settings“ sucht Ihr jetzt nach dem Eintrag

				
					access_log /var/log/nginx/access.log;

				
			

und ändern diesen in:

				
					access_log /var/log/nginx/access.log anonymized;

				
			

Speichert jetzt die Datei und testet die Änderungen mit

				
					sudo nginx -t

				
			

Hat alles geklappt starten wir Nginx neu

				
					sudo service nginx restart

				
			

Ruft eure Website jetzt einmal auf um eine neuen Eintrag in der Access Log zu generieren. Anschließend kontrollieren wir ob die letzten Stellen der IP Adresse genullt wurden.

				
					sudo nano /var/log/nginx/access.log

				
			

Die letzte Stelle der IP Adresse sollte ab sofort immer auf 0 gestellt werden.

Log Files automatisch löschen (empfohlen)

Logfiles sollten nach 7 Tagen gelöscht werden wenn diese personenbezogene Daten beinhalten. Wir haben die Daten bereits anonymisiert, die Änderung Logfiles statt 14 Tage nur 7 Tage aufzubewahren ist aber trotzdem keine schlechte Idee. Für die Umstellung sind auch nur ein paar zusätzliche Handgriffe notwendig. Zuerst öffnen wir die passende Konfigurationsdatei.

				
					sudo nano /etc/logrotate.d/nginx

				
			

In der Datei Ändern wir anschließend die Zahl neben „rotate“ von 14 auf 7. Der Inhalt der Datei sollte anschließend wie folgt aussehen.

				
					/var/log/nginx/*.log {
	daily
	missingok
	rotate 7
	compress
	delaycompress
	notifempty
	create 0640 www-data adm
	sharedscripts
	prerotate
	if [ -d /etc/logrotate.d/httpd-prerotate ]; then \
		run-parts /etc/logrotate.d/httpd-prerotate; \
	fi \
	endscript
	postrotate
		invoke-rc.d nginx rotate >/dev/null 2>&1
	endscript
}
				
			

Speichert die Datei und schließt den Editor. Wir müssen keinen service neu starten um die Änderungen zu übernehmen, da logrotate mittels crontab ausgeführt wird.

Nginx Service per Befehlszeile steuern

Damit Ihr mit Nginx ein bisschen fester im Sattel sitzt nachfolgend noch ein paar grundlegende Befehle zur Steuerung des Nginx Prozesses.

Nginx Server stoppen

				
					sudo systemctl stop nginx

				
			

Nginx Server starten

				
					sudo systemctl start nginx

				
			

Nginx Server neustarten

				
					sudo systemctl restart nginx

				
			

Nginx nach Änderungen von Einstellungen neu laden

				
					sudo systemctl reload nginx

				
			

Nginx Autostart deaktivieren

				
					sudo systemctl disable nginx

				
			

Nginx Autostart aktivieren

				
					sudo systemctl enable nginx

				
			

Nginx Server Logs

Sollte es zu Problemen kommen, legt Nginx z.B. Fehlermeldungen in den folgenden Dateien ab.

/var/log/nginx/access.log – Beinhaltet informationen zu allen Zugriffen
/var/log/nginx/error.log – Beinhaltet alle Fehlermeldungen

SSL Zertifikat einrichten

Für Anfragen die per HTTPS eintrudeln benötigen wir ein passendes Zertifikat. Unser Zertifikat erstelllen wir uns mit Let’s Encrypt selbst, dazu benötigen wir nur eine passende Domain die auf die IP Adresse unseres Servers zeigt. Mehr Details dazu findet Ihr weiter oben. Für die Einrichtung des Let’s Encrypt Zertifikats nutzen wir Certbot. Um die neueste Version des Packages zu erhalten, fügen wir zuerst das Repository der Entwickler hinzu.

				
					sudo add-apt-repository ppa:certbot/certbot

				
			

Bestätigt die Eingabe mit Enter und drückt anschließend nochmals Enter um die Installation zu bestätigen. Jetzt installieren wir den Certbot für Nginx.

				
					sudo apt install python-certbot-nginx

				
			

Dank des speziell für Nginx entwickelten Plugins ist doe Konfiguration des Zertifikats schnell erledigt. Ändert im Befehl die jeweiligen Domainnamen auf eure Domain. Nach der Bestätigung müsst Ihr eine E-Mail Adresse angeben und die AGB annehmen. Let’s Encrypt bestätigt anschließend das die gewählte Domain wirklich auf den Server zeigt. Zusätzlich habt Ihr die Möglichkeit alle HTTP Anfragen direkt zu HTTPS umzuleiten. Diese Option solltet Ihr unbedingt aktivieren. Anschließend wird das Zertifikat erstellt und automatisch für euren Nginx Server Block konfiguriert.

				
					sudo certbot --nginx -d euredomain.com -d www.euredomain.com

				
			

Output:

				
					Please choose whether or not to redirect HTTP traffic to HTTPS, removing HTTP access.
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
1: No redirect - Make no further changes to the webserver configuration.
2: Redirect - Make all requests redirect to secure HTTPS access. Choose this for
new sites, or if you're confident your site works on HTTPS. You can undo this
change by editing your web server's configuration.
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Select the appropriate number [1-2] then [enter] (press 'c' to cancel): 2
Redirecting all traffic on port 80 to ssl in /etc/nginx/sites-enabled/euredomain.com
Redirecting all traffic on port 80 to ssl in /etc/nginx/sites-enabled/euredomain.com

- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Congratulations! You have successfully enabled https://euredomain.com and
https://www.euredomain.com

You should test your configuration at:
https://www.ssllabs.com/ssltest/analyze.html?d=euredomain.com
https://www.ssllabs.com/ssltest/analyze.html?d=www.euredomain.com
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

IMPORTANT NOTES:
 - Congratulations! Your certificate and chain have been saved at:
   /etc/letsencrypt/live/euredomain.com/fullchain.pem
   Your key file has been saved at:
   /etc/letsencrypt/live/euredomain.com/privkey.pem
   Your cert will expire on 2019-05-22. To obtain a new or tweaked
   version of this certificate in the future, simply run certbot again
   with the "certonly" option. To non-interactively renew *all* of
   your certificates, run "certbot renew"
 - Your account credentials have been saved in your Certbot
   configuration directory at /etc/letsencrypt. You should make a
   secure backup of this folder now. This configuration directory will
   also contain certificates and private keys obtained by Certbot so
   making regular backups of this folder is ideal.
 - If you like Certbot, please consider supporting our work by:

   Donating to ISRG / Let's Encrypt:   https://letsencrypt.org/donate
   Donating to EFF:                    https://eff.org/donate-le
				
			

Das hat geklappt. Besucht jetzt eure Domain, die Anfrage die vorher über http:// durchgegangen ist, sollte jetzt auf https:// weitergeleitet werden. Sofern euer Browser keine Warnmeldung im Bezug auf das verwendete Zertifikat anzeigt sind wir so gut wie fertig. Let’s Encrypt Zertifikate haben ein Ablaufdatum, wir müssen also noch testen ob die automatische Verlängerung auch wirklich funktioniert. Dafür führen wir den folgenden Befehl aus.

				
					sudo certbot renew –dry-run

				
			

Output:

				
					Congratulations, all renewals succeeded. The following certs have been renewed:
  /etc/letsencrypt/live/euredomain.com/fullchain.pem (success)
** DRY RUN: simulating 'certbot renew' close to cert expiry
**          (The test certificates above have not been saved.)
				
			

MySQL Server installieren und konfigurieren

Eine MySQL Datenbank darf auf unserem Server natürlich nicht fehlen. Wir starten also direkt die Installation.

				
					sudo apt install mysql-server

				
			

MySQL bietet einen Wizard der uns durch die Installation führt und uns auf diverse wichtigen Themen aufmerksam macht. Den Wizard starten wir mit folgendem Befehl:

				
					sudo mysql_secure_installation

				
			

Output:

				
					Securing the MySQL server deployment.

Connecting to MySQL using a blank password.

VALIDATE PASSWORD PLUGIN can be used to test passwords
and improve security. It checks the strength of password
and allows the users to set only those passwords which are
secure enough. Would you like to setup VALIDATE PASSWORD plugin?
				
			

Das Validate Password Plugin hilft dabei unsichere Kennwörter zu blockieren. Wir nutzen das Plugin und bestätigen mit „y“

				
					There are three levels of password validation policy:

LOW    Length >= 8
MEDIUM Length >= 8, numeric, mixed case, and special characters
STRONG Length >= 8, numeric, mixed case, special characters and dictionary  file

Please enter 0 = LOW, 1 = MEDIUM and 2 = STRONG:
				
			

Nun müssen wir uns entscheiden wie scharf die Passwortkontrolle ablaufen soll. Ich wähle hier Medium (also die Option 1), da es ein guter Kompromiss zwischen Sicherheit und Nutzbarkeit ist.

				
					Please set the password for root here.

New password:
				
			

Gebt jetzt das gewünschte Passwort mit Berücksichtigung der Vorgaben ein und bestätigt die Eingabe. Alle weiteren Abfragen sollten mit „y“ bestätigt werden.

Output:

				
					By default, a MySQL installation has an anonymous user,
allowing anyone to log into MySQL without having to have
a user account created for them. This is intended only for
testing, and to make the installation go a bit smoother.
You should remove them before moving into a production
environment.

Remove anonymous users? (Press y|Y for Yes, any other key for No) : y
Success.


Normally, root should only be allowed to connect from
'localhost'. This ensures that someone cannot guess at
the root password from the network.

Disallow root login remotely? (Press y|Y for Yes, any other key for No) : y
Success.

By default, MySQL comes with a database named 'test' that
anyone can access. This is also intended only for testing,
and should be removed before moving into a production
environment.


Remove test database and access to it? (Press y|Y for Yes, any other key for No) : y
 - Dropping test database...
Success.

 - Removing privileges on test database...
Success.

Reloading the privilege tables will ensure that all changes
made so far will take effect immediately.

Reload privilege tables now? (Press y|Y for Yes, any other key for No) : y
Success.

All done!
				
			

Das wars auch schon wieder, MySQL ist jetzt auf dem Server eingerichtet. Sofern Ihr phpMyAdmin nutzen möchtet, solltet Ihr dafür einen eigenen Nutzer anlegen. Aus Sicherheitsgründen solltet Ihr bei der Erstellung eines neuen Nutzers ausschließlich Verbindungen über den localhost zulassen. Für die Erstellung verbinden wir uns zuerst mit der Datenbank.

				
					sudo mysql

				
			

Neuen Nutzer erstellen:

				
					CREATE USER 'username'@'localhost' IDENTIFIED BY 'deinpw';
GRANT ALL PRIVILEGES ON *.* TO 'phpmyadmin'@'localhost' WITH GRANT OPTION;
FLUSH PRIVILEGES;
				
			

Diesen erstellten Nutzer kann man anschließend z.B. für phpMyAdmin nutzen um auf die Datenbank zuzugreifen. Nutzer können auch auf die jeweiligen Datenbanken beschränkt werden.

Zusätzliche Server Sicherheit

Fail2Ban

Wir verbinden uns über das Internet mit unserem Server, was bedeutet das andere dies theoretisch auch tun können. Speziell beim Einsatz einer simplen „User/Passwort“ Authentifizierung können Angreifer z.B. mittels Bruteforce millionenfach Kennwörter ausprobieren um Zugang zum Server zu erlangen. Solltet Ihr euch per SSH Keys mit dem Server verbinden habt Ihr bereits einen Vorteil, eine zusätzliche Sicherheitsabfrage ist aber immer eine gute Idee. Fail2Ban überwacht die Logfiles eures Servers und sucht nach gescheiterten Login Versuchen und setzt bei einer von euch gewählten Anzahl an gescheiterten Versuchen die IP des Angreifers auf eine Sperrliste. Angreifer haben damit also z.B. nur 3 Versuche euer Kennwort herauszufinden bevor die Sperre greift und der Server alle Verbindungen zu der jeweiligen Adresse ablehnt. Jetzt stellt sich natürlich die Frage, ob dies auch mit der DSGVO vereinbar ist. Meiner Meinung nach greift hier das berechtigte Interesse nicht gehacked zu werden und natürlich auch die Pflicht Daten zu schützen. Die Entscheidung für oder gegen Fail2Ban liegt aber bei euch, für fundierte rechtliche Auskunft bin ich leider nicht die richtige Ansprechperson.

Nichts desto trotz hier eine schnelle Einführung in Fail2Ban.

Installation:

				
					sudo apt-get install fail2ban
				
			

Aktivierung des Prozesses beim Serverstart und starten von Fail2Ban

				
					sudo systemctl start fail2ban
sudo systemctl enable fail2ban
				
			

Der service sollte jetzt laufen, wir brauchen nur noch eine passende Config Datei, diese erstellen wir mit:

				
					sudo nano /etc/fail2ban/jail.local

				
			

In die Datei fügen wir die folgende Startkonfiguration ein:

				
					[sshd]
enabled = true
port = 22
filter = sshd
logpath = /var/log/auth.log
maxretry = 3
				
			

Speichert die Datei jetzt und schließt den Editor mit STRG + X. Um die Änderungen zu übernehmen starten wir den service neu.

				
					sudo systemctl restart fail2ban

				
			

Ab sofort werden Angreifer nach drei fehlgeschlagenen Loginversuchen ausgesperrt. Ihr könnt Fail2Ban jetzt natürlich selbst ausprobieren, geht davor aber auf Nummer sicher, dass Ihr abseits von SSH noch eine Möglichkeit habt euch mit dem Server zu verbinden.

IP Adresse aus Sperrliste entfernen:

Um eine IP Adresse aus der Sperrliste zu löschen könnt Ihr folgenden Befehl verwenden (statt IP_ADRESSE muss natürlich die betroffene IP Adresse angegeben werden:

				
					sudo fail2ban-client set sshd unbanip IP_ADRESSE

				
			

Damit habt Ihr Fail2Ban rudimentär konfiguriert. Mehr über die Benutzung dieses essentiellen Tools bekommt Ihr über die Kommandozeile:

				
					man fail2ban

				
			

Fazit

Euer Server ist jetzt bereit für den Einsatz. Speziell in Sachen Sicherheit gibt es viele Möglichkeiten euren Server vor unbefugten Zugriffen zu schützen. In den nächsten Schritten könnt Ihr euch z.B. über Server Monitoring /blog/linux-root-server-vserver-monitoring informieren. Auch in Sachen Sicherheit gibt es noch einige Punkte die wir in dieser Anleitung nicht durchgegangen sind. Solltet Ihr über eine statische IP Adresse ins Internet gehen empfiehlt es sich auch den Zugang zu SSH auf eure IP-Adresse einzuschränken. Externe Anfragen die nicht von euch kommen werden dadurch direkt blockiert. Es gibt immer was zu lernen und das ist auch gut so.

Linux Root-Server / vServer Monitoring

Ein eigener Root Server oder vServer liefert die eigene Website oder App merklich schneller aus, als es bei Shared Hosting Paketen der Fall ist. Viele Frameworks wie z.B. Laravel benötigen sogar einen eigenen Server um alle Funktionen optimal nutzen zu können. Der Vorteil eines eigenen Servers liegt in der Freiheit Einstellungen und die genutzte Software komplett selbst verwalten zu können. Diese Vorteile sind aber gleichzeitig auch Nachteile, da der Administrationsaufwand im Vergleich zum Shared Hosting komplett auf den Inhaber übergeht. Man ist selbst dafür verantwortlich, dass der eigene Server richtig funktioniert und bestmöglich abgesichert ist. Neben der richtigen Konfiguration empfiehlt sich die Implementation von Monitoring Apps die z.B. Benachrichtigungen ausschicken, wenn ein Dienst nicht mehr richtig funktioniert, oder vielleicht sogar der ganze Server ausfällt.

Für den eigenen Server gibt es in Sachen Monitoring diverse Lösungsansätze. Werfen wir zuerst einen Blick auf die einfacheren Tools.

UptimeRobot

UptimeRobot ist ein kostenloser Dienst der automatisiert Pings an IP-Adressen oder Domains sendet und bei Nichterreichbarkeit der Zieladresse eine automatisierte E-Mail verschickt. Der Dienst kontrolliert dabei ausschließlich ob der jeweilige Server eine Antwort schickt, nicht aber ob die eigentliche Website richtig angezeigt wird. Eine fehlerhafte WordPress Installation die Fehlermeldungen ausspuckt wird von UptimeRobot also trotzdem als online markiert.

htop zur Prozessüberwachung

Ein weiteres einfaches Tool zur Überwachung eures Root Server hört auf den Namen „htop“. Das Tool zeigt die derzeit ausgeführten Prozesse und sortiert diese Standardmäßig anhand der CPU Auslastung. Sollte euer Server z.B. ungewohnt langsam auf Anfragen reagieren könnt Ihr htop heranziehen um herauszufinden, was auf eurer Maschine gerade passiert. Neben den verbrauchten CPU Ressourcen wird auch die Menge an genutzten Arbeitsspeichers des jeweiligen Prozesses angezeigt. In der linken oberen Ecke gibt es weitere Details die schnell zeigen, wie es um euren Server derzeit steht. Leider bietet htop keine automatische Reporting Funktion an, es ist also nicht möglich bei hoher Belastung automatisch Benachrichtigungen auszusenden.

Installation

				
					sudo apt-get install htop
				
			

Logwatch

Unter den Monitoring Tools die automatisch Benachrichtigungen versenden und direkt am eigenen Server ausgeführt werden, stellt Logwatch die einfachste Lösung dar. Das Programm schickt auf Wunsch einmal täglich eine Zusammenfassung der wichtigsten Logs per E-Mail an den Administrator. Der Report kann auf Wunsch im HTML Format aufgeschlüsselt werden um eine bessere Übersicht zu ermöglichen. Welche Arten von Problemen aufgezeichnet und übertragen werden sollen, kann selbst konfiguriert werden. Mehr Infos gibt es in der offiziellen Dokumentation direkt bei Ubuntu.

Installation

				
					sudo apt-get install logwatch
				
			

NetData Performance Monitoring

Möchte man die Performance von mehreren Servern im Blick behalten empfiehlt sich z.B. NetData. Das Tool bietet eine gut gelungene Oberfläche die über die aktuellen Auslastungen der jeweiligen Server informiert. Es können auf Wunsch automatisierte Warnungen ausgesendet werden, wenn ein überwachter Prozess den Server komplett auslastet. Die Oberfläche zeigt auf Wunsch auch auf einen Blick die Auslastung des Prozessors, den freien Arbeitsspeicher, die Netzwerkauslastung oder die Anzahl der laufenden Prozesse.

Mehr Infos zu NetData

Nagios 4

Nagios ist eines der bekanntesten Monitoring Tools das neben Servern auch die Netzwerk-Infrastruktur in einem Unternehmen überwachen kann. Dem Einsatz als Monitoring-Tool eines Linux Servers steht also nichts im Weg. Nagios wird als Server / Client aufgesetzt. Auf eurem Rechner läuft z.B. der Nagios Server der sich Informationen von seinen eingerichteten Clients (eurem Root Server oder vServer) holt. Für Windows bietet Nagios hierfür z.B. ein VM-Image an das direkt ausgeführt werden kann. Auf dem Root Server muss anschließend noch die passende Software installiert, Ports auf der Firewall geöffnet und eine Verbindung zwischen eurem Nagios Server und dem Client hergestellt werden. Die Konfiguration nimmt etwas Zeit in Anspruch, spart euch anschließend aber speziell bei der Verwaltung mehrerer Server viel Zeit. Für den Einsatz mit nur einem Server kann Nagios schnell zu Komplex sein.

Die Einrichtung von zu überwachenden Clients wird bei Nagios durch den Konfigurationsassistenten vereinfacht, setzt aber trotzdem Erfahrungen mit Linux voraus. Der Konfigurationsassistenten bietet Support für Digital Ocean, Amazon EC2, die Microsoft Azure Cloud, Docker oder die Google Cloud. Per Knopfdruck funktioniert die Installation auf Clients aber nicht. Nagios kann auch zur Überwachung eures Heimservers genutzt werden.

Wer sich für das Monitoring interessiert sollte sich Nagios XI also direkt z.B. als VM Image herunterladen und ausprobieren.

Mehr Infos zu Nagios

WordPress Ladezeiten PageSpeed Insights optimieren

Inhaltsverzeichnis

Um die eigene Website in den Suchergebnissen auf gute Plätze zu bringen müssen viele Aspekte der Seite gut abgestimmt sein. Besonders wichtig sind informative Texte die mit passenden Keywords bestückt wurden oder qualitativ hochwertige Links die auf die eigene Seite zeigen. Mit dem immer weiter steigenden Anteil an Smartphones und Tablets (zum Zeitpunkt des Beitrags gut 45% aller Nutzer im Internet) die zum surfen genutzt werden, wird für Suchmaschinen wie Google auch die Geschwindigkeit der jeweiligen Seiten wichtiger. Wie stark sich die Geschwindigkeit einer Website auf die Reihung in den Suchergebnissen auswirkt, gibt Google nicht direkt an, ein Ranking-Faktor ist sie aber definitiv. Ein Indiz dafür ist z.B. das zuletzt stark überarbeitete PageSpeed Insights Tool von Google. Mit diesem Helferlein kann man die eigenen Website testen und erhält auch direkt Verbesserungsvorschläge. Ziel ist es Websites schneller und gleichzeitig schlanker zu machen. Dies ermöglicht es Nutzern mit einer langsamen Internetverbindung oder einem Gerät mit wenig Leistung trotzdem schnell von Seite zu Seite springen zu können.

In diesem Beitrag nehmen wir uns einen mittlerweile archivierten Blog vor und steigern dessen PageSpeed-Wertung. Der Blog basiert auf WordPress sowie einem eigens entwickelten Theme. Für die Optimierung machen wir uns kostenlos verfügbare Plugins und Tools zunutze und sprechen auch über die jeweiligen Empfehlungen von Google selbst.

Ausgangssituation

Unser Blog hat mit 62 Punkten eine Wertung die im unteren Mittelfeld einzuordnen ist. Es gibt also genügend Verbesserungsmöglichkeiten die mit großer Wahrscheinlichkeit auch auf eurem Blog oder eurer Website umgesetzt werden können.

Der erste Punkt den wir unter den von Google vorgeschlagenen Empfehlungen finden, ist die Beseitigung von Ressourcen die das Rendering blockieren bzw. verlangsamen. Gemeint sind damit Stylesheets sowie JavaScript Files die vom Browser beim Besuch heruntergeladen und interpretiert werden müssen. Je mehr Dateien vom Browser dabei abgerufen und interpretiert werden, desto länger die Zeit bis die eigentliche Website am Schirm des Nutzers angezeigt wird. Eine optimale Lösung wäre an dieser Stelle das Zusammenfügen aller benötigten .CSS sowie .JS Dateien. WordPress Plugins die im Frontend der Seite zum Einsatz kommen, haben die unangenehme Eigenschaft, jeweils eigene CSS und auch JavaScript Dateien einzubinden. Jedes installierte Plugin kann uns also theoretisch ausbremsen.

Ein praktisches Plugin zur Kombinierung von JS und CSS Dateien ist das kostenlose WordPress Plugin W3 Total Cache. Das Caching-Plugin übernimmt dabei gleich mehrere Aufgaben die uns das Leben spürbar erleichtern werden. 

W3 Total Cache Einstellungen

General Settings

Nach der Installation von W3 Total Cache findet sich im Admin Panel ein neuer Reiter unter dem man die grundlegenden Einstellungen zu W3 Total Cache vornehmen kann. Das Caching Plugin geht nach der Installation nicht automatisch ans Werk. Die jeweiligen Funktionen müssen erst von Hand aktiviert und getestet werden. Viele der Optionen die wir in diesem Beitrag durchgehen können auf eurer Website oder eurem Blog zu Problemen führen. Nach der Aktivierung der jeweiligen Optionen empfiehlt es sich die eigene Website zu testen um herauszufinden ob auch wirklich noch alles so wie gewünscht funktioniert. 

Page Cache

WordPress erstellt Inhalte bei jedem Seitenbesuch neu. Für jeden Besucher werden z.B. Datenbankabfragen abgeschickt um die Informationen der angefragten Seite anzeigen zu können. Diese Anfragen verzögern den Seitenaufbau und können bei stark frequentierten Seiten schnell zu größeren Problemen wie einer überlasteten Datenbank führen. Mithilfe des Page Cache Features werden statische Versionen der jeweiligen Seiten gespeichert die anschließend direkt aufgerufen werden können. Die verfügbaren Cache Methoden sind abhängig von den am Server installierten Funktionen. Installationen die auf normalen Webspace installiert sind können in den meisten Fällen ohne bedenken auf Disk: Enhanced gestellt werden.

Minify

Die Minify Funktion ist eine sehr effektive Methode um CSS, HTML und JavaScript Code zu verkleinern. CSS Code der z.B. in 4 verschiedenen Dateien aufgeteilt eingebunden wird, kann nach der Aktivierung automatisch in eine einzelne Datei zusammengefasst werden. Aus vier Anfragen an den Server wird also eine einzige. Leider kann diese Einstellung oftmals nicht problemlos aktiviert werden. Speziell bei mehreren eingebundenen JavaScript Files kann es bei der Komprimierung und Zusammenfassung zu Problemen kommen. Nach der Aktivierung von Minify sollten alle Funktionen auf eurer Seite getestet werden. Die Entwicklerkonsole eures Browser kann auch schnell Auskunft darüber geben, ob etwaige JavaScript Fehler nach der Umstellung auftreten. Tipp: Solltet Ihr den Page Cache bereits aktiviert haben, müsst Ihr nach jeder Änderung den aktuell erstellten Cache über die Option „Performance“-> „Purge all Caches“ in der Adminleiste löschen.

Sollte es zu Problemen nach der Umstellung auf Minify kommen, kann versucht werden unter dem Menüpunkt „Minify“ weitere Einstellungen zu treffen. Unter „JS“ kann anschließend definiert werden wie Minify mit JavaScript Dateien umgeht. Unter den Optionen findet sich z.B. der Punkt „Operations in areas“. Hier kann angegeben werden wie JavaScript Dateien eingebunden werden sollen. Hier muss darauf geachtet werden, dass JS Code der z.B. mit „async“ gekennzeichnet wird, nicht sofort beim Seitenbesuch ausgeführt wird. Dies führt z.B. bei Cookie Bannern dazu, dass diese nicht mehr angezeigt werden. Bei Problemen kann man versuchen auf „Combine only“ umzustellen. Solltet Ihr Plugins nutzen die nach der Umstellung Probleme bereiten, könnt Ihr euch z.B. nach alternativen umsehen die eventuell besser mit der Komprimierung zurecht kommen. Probleme gibt es der Erfahrugn nach speziell mit älteren Plugins die bereits seit einiger Zeit nicht mehr aktualisiert wurden. Führen diese Einstellungen nicht zum gewünschten Erfolg kann man in letzter Instanz leider nur die Komprimierung von JavaScript deaktivieren. In meinem Fall ist die Komprimierung kompatibel, Glück gehabt.

Hat Minify geklappt, kann man direkt einen Blick auf den Quellcode der Seite werfen. Aus dem schön verschachtelten Code sollte ein unlesbarer Schwall an HTML geworden sein. Dieser Code ist für das menschliche Auge zwar nicht schön anzusehen und schon gar nicht übersichtlich, stellt für Browser aber kein Problem dar. Die gesparten Zeilen führen zu kleineren Dateigrößen und schnelleren Ladezeiten. JavaScript und CSS Code ist jetzt auch in passende Dateien zusammengefasst worden.

Object Cache und Database Cache

Für einfache Blogs sollte die Geschwindigkeit durch Page Caching und die Änderungen durch Minify bereits merklich gesteigert worden sein. Sollten sich auf eurem WordPress Blog auch Datenbankintensive Anwendungen finden, empfiehlt sich die Nutzung des Database Cache-Features. Dieses speichert Resultate von Datenbankabfragen und kann diese anschließend schneller ausliefern. Neben dem Database Cache gibt es auch die Möglichkeit den in WordPress implementierten Object Cache für längere Zeit zu speichern. Der von WordPress verwendete Cache wird im Auslieferungszustand bei jedem Seitenaufbau neu erstellt. Die Lebenszeit dieses Caches endet mit der Auslieferung der Website. Die Daten im Cache werden anschließend gelöscht. W3 Total Cache gibt hier die Möglichkeit diesen Cache länger zu speichern was wiederkehrende Scriptausführungen merklich schneller machen kann und die Datenbank weiter entlastet.

Browser Cache

Browser Caching ist ein weiteres wichtiges Tool in der Optimierung der Ladezeit eines WordPress Blogs. Mit dieser Funktion werden Inhalte wie JavaScript, CSS oder Bilder mit einem Ablaufdatum gekennzeichnet. Dieses Ablaufdatum gibt dem Browser des Besuchers zu verstehen, dass sich die markierten Dateien nicht regelmäßig ändern, sondern zwischengespeichert werden können. Als Beispiel, ein Besucher kommt auf eine Website, ladet den Stylesheet, JavaScript, das Logo sowie HTML Code der für die Anzeige der Inhalte verwendet wird. Unsere Seite gibt an, dass der Stylesheet, JavaScript und das Logo für 30 Tage aktuell sind. Springt ein Besucher anschließend auf eine weitere Unterseite fragt sein Browser den Stylesheet, bereits geladenen JavaScript Code sowie das Logo nicht erneut vom Server ab, sondern greift darauf direkt aus seinem eigenen Zwischenspeicher zu. Die benötigten Daten müssen also nicht nochmals heruntergeladen werden, das spart Zeit und Ressourcen.

Zum Browser Caching finden sich unter „Browser Caching“ im linken Menü weitere Optionen. Unter den erweiterten Optionen empfiehlt es sich für die jeweiligen Dateitypen einen „Expire Header“ mitzuschicken. Dies kann dabei helfen, den Browser des Besuchers davon zu überzeugen die gekennzeichneten Dateien auch wirklich in den lokalen Cache aufzunehmen. Aktiviert hierzu die Option „Set expires header“.

Sollte es in eurem Fall Probleme mit W3 Total Cache geben können die Einstellungen für Browser Caching auch direkt in eurer .htaccess Datei getroffen werden. Am Anfang der Datei kann dazu der folgende Code eingefügt werden.

				
					# BROWSER CACHING #
ExpiresActive On
ExpiresByType text/css "access 1 month"
ExpiresByType text/html "access 1 month"
ExpiresByType image/gif "access 1 year"
ExpiresByType image/png "access 1 year"
ExpiresByType image/jpg "access 1 year"
ExpiresByType image/jpeg "access 1 year"
ExpiresByType image/svg "access 1 year"
ExpiresByType image/x-icon "access 1 year"
ExpiresByType application/pdf "access 1 month"
ExpiresByType application/xhtml-xml "access 1 month"
ExpiresByType application/javascript "access 1 month" 
ExpiresByType text/x-javascript "access 1 month"
ExpiresByType application/x-shockwave-flash "access 1 month"
ExpiresDefault "access 1 month"
# BROWSER CACHING #
				
			

Gzip / Deflate Komprimierung

In den Browser Cache Einstellungen findet sich zusätzlich eine weitere wichtige Funktion zur Komprimierung von textbasierten Inhalten. Wird die Option „Enable HTTP(gzip) compression“ aktiviert übertragt der Server eine komprimierte Version der Inhalte die anschließend vom Browser entpackt und angezeigt werden. Diesen Vorgang kann man sich wie bei einer klassischen .zip Datei vorstellen. Dies verkleinert die übertragenen Datenmengen und ermöglicht dadurch einen schnelleren Ladevorgang speziell auf mobilen Geräten mit langsamen Internetverbindungen. Bilder werden absichtlich nicht komprimiert übertragen, da gängige Formate wie JPG oder PNG bereits komprimiert sind. Eine zusätzliche Komprimierung belastet nur unnötig die Serverkapazitäten und bietet keinerlei Vorteile.

Sollte die gzip Kompression über W3 Total Cache nicht funktionieren können die passenden Einstellungen auch direkt in die .htaccess Datei geschrieben werden. Der folgende Code ist für den Einsatz auf Apache Servern gedacht. Solltet Ihr ein Webspace Paket nutzen trifft dies in den meisten Fällen auch auf euch zu.

				
					<IfModule mod_deflate.c>
AddOutputFilterByType DEFLATE application/atom+xml
AddOutputFilterByType DEFLATE application/javascript
AddOutputFilterByType DEFLATE application/json
AddOutputFilterByType DEFLATE application/rss+xml
AddOutputFilterByType DEFLATE application/vnd.ms-fontobject
AddOutputFilterByType DEFLATE application/x-font-ttf
AddOutputFilterByType DEFLATE application/x-web-app-manifest+json
AddOutputFilterByType DEFLATE application/xhtml+xml
AddOutputFilterByType DEFLATE application/xml
AddOutputFilterByType DEFLATE font/opentype
AddOutputFilterByType DEFLATE image/svg+xml
AddOutputFilterByType DEFLATE image/x-icon
AddOutputFilterByType DEFLATE text/css
AddOutputFilterByType DEFLATE text/html
AddOutputFilterByType DEFLATE text/plain
AddOutputFilterByType DEFLATE text/x-component
AddOutputFilterByType DEFLATE text/xml
AddOutputFilterByType DEFLATE text/javascript
</IfModule>
				
			

Zwischenanalyse – Spürbar verbessert

Mit W3 Total Cache haben wir eine breite Palette an Performance Verbesserungen vornehmen können. Werfen wir einen kurzen Blick auf unsere PageSpeed Insights Bewertung.

Unsere Optimierungen haben uns direkt 24 Punkte eingebracht und die Ladezeiten der Seite sollten bereits merklich schneller sein. Ganz am Ziel sind wir aber noch nicht. Es gibt noch ein paar Optimierungen die teilweise recht schnell umgesetzt werden können. 

Lazy Loading

Findet ein Besucher den Weg auf unsere Website werden standardmäßig alle Inhalte beim Seitenaufruf geladen. Darunter fallen auch z.B. Bilder die auf der Seite weiter unten und somit nicht im Sichtfeld des Betrachters zu sehen sind. Mithilfe von Lazy Loading werden nicht unmittelbar wichtige Bilder erst kurz bevor sie zu sehen sind geladen. Der Seitenaufbau läuft dadurch, speziell auf mobilen Geräten mit langsamer Internetverbindung, spürbar schneller ab. Wer auf eine Lupenreine Bewertung von W3C Wert legt, sollte auf diese Lösung verzichten. Bilder werden bei Lazy Loading standardmäßig mit einer eigenen CSS-Klasse ausgestattet und verlieren Ihren „src“ Tag was bei der Validierung der Seite zu Problemen führen kann. Vom Standpunkt der Suchmaschinenoptimierung aus gesehen fallen die verbesserten Ladezeiten aber deutlich stärker ins Gewicht als der zugrundeliegende Code.

Für WordPress gibt es diverse fertige Plugins die euren Blog um Lazy Loading erweitern. Ich habe mich für BJ Lazy Load entschieden. Über die Einstellungen kann man definieren welche Medien per Lazy Load gesteuert werden sollen. Weiters kann man sich dafür entscheiden ein Platzhalter-Bild anzuzeigen bis die jeweilige Ressource fertig nachgeladen wurde. Diese kleine Änderung bringt uns eine nochmals verbesserte Ladezeit, Google’s PageSpeed Insights bewertet uns jetzt mit der folgenden Punktezahl.

Zwischenanalyse – Fast geschafft

Ein recht guter Wert, nicht perfekt aber doch beachtlich. Um an noch mehr Punkte zu kommen, müssen wir einen Blick auf die restlichen Empfehlungen von Google werfen.

Bilder richtig dimensionieren

Dieser Punkt zeigt Bilder die auf der Website skaliert angezeigt werden. Ein Bild mit einer Abmessung von 500×500 das auf der Website in 250×250 angezeigt wird, könnte uns an dieser Stelle z.B. aufgezeigt werden. Sollten Meldungen dieser Art bei euch angezeigt werden, hilft es die Größe der verwendeten Thumnails anzupassen. Hierfür muss man z.B. die vom eigenen Theme genutzten Thumbnail-Größen anpassen. Die dafür benötigten Optionen sind von Theme zu Theme an unterschiedlichen Stellen zu finden. In den meisten Fällen finden sich die Angaben zu den Thumbnails direkt in der functions.php Datei. Sucht am besten nach der Funktion „add_image_size“. Weitere Informationen zur Nutzung dieser Funktion finden sich in der offiziellen WordPress Code Reference.

Ressourcen beseitigen, die das Rendering blockieren

Bei diesem Vorschlag scheiden sich die Geister. Google empfiehlt unter anderem nicht verwendeten CSS Code aufzuschieben bzw. nur dann zu laden wenn er auf der Seite auch wirklich benötigt wird. Der für die Seite am wichtigsten CSS Code, wie Font-Informationen, Hintergrundfarben sowie andere Grundlegenden Style Informationen sollen direkt in den Quellcode eingebaut werden. Wichtiger JavaScript Code soll auch direkt in den Quellcode verlegt werden. JavaScript-Code der für die eigentliche Anzeige der Inhalte nicht notwendig ist, kann man z.B. mithilfe des Attributs „defer“ aufgeschoben werden. Eingebundenes JavaScript das per defer eingebunden wurde, wird erst ausgeführt wenn die Website komplett geladen und vom Browser interpretiert wurde. Alternativ kann der JavaScript Code aus dem Header in den Footer Bereich der Website verfrachtet werden und blockiert dadurch den Seitenaufruf nicht mehr. 

Nutzt man mehrere Plugins die Frontend Funktionalitäten anbietet kann es schwer werden, diese Art der Optimierung durchzuführen. Viele JavaScript Funktionen die bei diversen fertigen Themes eingebaut sind, müssen direkt beim Aufruf der Website ausgeführt werden. Ändert man den Zeitpunkt an dem JavaScript geladen wird, kann es zu Anzeigefehlern oder komplett fehlenden Funktionen kommen. Problematisch kann sich auch die Umsetzung der Vorgaben für Stylesheets gestalten. Wird der für die Anzeige der Website benötigte CSS Code zu spät geladen, kann es zu Anzeigeproblemen kommen. Google empfiehlt wichtigen CSS Code direkt in den Quellcode der Seite abzulegen. Damit ist z.B. CSS Code gemeint der den allgemeinen Aufbau eurer Seite wie die Abmessungen der wichtigsten div Container, die gewählte Schriftart oder die zu verwendenden Farben beschreibt. 

Mithilfe von Minify haben wir diese Dateien zuvor zusammengefügt und uns damit bereits Ladezeiten eingespart. Ein Großteil der Plugins bietet nicht die Option CSS Code Inline auf der Website darzustellen, bis vor kurzem war diese Praktik auch bei Plugins die z.B. bei ThemeForest angeboten werden verboten. Dies macht die Umsetzung dieser Vorgabe nochmals deutlich schwieriger. Hier sind wir auch schon bei der Frage angelangt ob die Optimierung der Stylesheet Informatioenn wirklich Sinn macht. Unsere Seite lädt zwar nach der Umstellung um ein paar Millisekunden schneller, dafür müssen wir aber ggf. anzeigefehler in Kauf nehmen. Fraglich ist auch der Vorschlag von Google nicht verwendeten CSS Code aufzuschieben. Damit ist gemeint, dass wir den verwendeten Stylesheet auf jeder Seite so anpassen, dass dieser auch wirklich nur die Elemente beschreibt die auch wirklich zu sehen sind. Damit sparen wir zwar Datenverkehr, der Browser des Besuchers kann aber beim Besuch weiterer Unterseiten nicht auf die bereits zwischengespeicherte Version des Stylesheets zurückgreifen, da sich dieser von der vorherigen Seite unterscheidet. Der erste Besuch wäre somit um ein paar Millisekunden schneller, dafür aber auf weiteren Unterseiten jeweils ein paar Millisekunden langsamer. 

In vielen Fällen ist es nicht ohne größerem Aufwand möglich, dies Probleme aus der Welt zu schaffen. Es ist auch mehr als fraglich ob diese Optimierung den Aufwand wert ist. Die Zeit die hier verschlungen wird, wäre wohl mit ziemlicher Sicherheit besser in die Suche nach neuen Backlinks investiert.

Für diejenigen unter euch die sich mit dieser Option trotzdem auseinandersetzen möchten hier ein paar Lösungsansätze.

Scripts per W3 Total Cache in den Footer verschieben

Um bei der Nutzung von W3 Total Cache die Scripts schnell in den Footer zu verschieben müsst Ihr die footer.php eures Themes bearbeiten. Eine Zeile vor </body> fügt Ihr die folgenden HTML Kommenater ein. Anstelle der eingefügten HTML Kommentare werden von W3 Total Cache Styles und Scripts die für die Ausführung im Header eingeplant waren erst im Footer Bereich eingefügt.

				
					<!-- W3TC-include-js-head -->
<!-- W3TC-include-js-body-start -->
<!-- W3TC-include-js-body-end -->
<!-- W3TC-include-css -->
				
			

Der Name des Tags gibt jeweils an ob CSS oder JS Dateien an dieser Stelle eingefügt werden sollen. Nach der Umstellung sollten alle Funktionen eurer Seite getestet werden. Öffnet dazu auch die Entwicklerkonsole und werft einen Blick auf die „Console“, dort werden euch mögliche JavaScript Fehlermeldungen angezeigt. Um die Fehlersuche zu vereinfachen könnt Ihr auch die zuvor aktivierte Minify Funktion deaktivieren. Dadurch werden Fehlermeldungen einer JavaScript Datei zugeordnet die anschließend direkt mit einem problematischen Plugin in Verbindung gebracht werden kann.

Bilder in modernen Formaten bereitstellen

Nicht alle Dateiformate sind optimal für die Darstellung von Bildern im Web. PageSpeed Insights hat Probleme mit Formaten wie PNG, speziell wenn diese größer als unbedingt notwendig sind. Dienste wie TinyPNG können hier schnell Abhilfe schaffen indem die Dateien verlustfrei komprimiert werden. An dieser Stelle zeigt PageSpeed in eurem Fall höchstwahrscheinlich auch an, dass weitere Bilder optimiert werden können. WordPress Plugins wie reSmush.it ermöglichen es hochgeladene Bilder direkt zu verkleinern bzw. zu optimieren. Im Fall von reSmush.it gibt es auch die Möglichkeit alle bislang hochgeladene Bilder zu optimieren. Nachteil an reSmush.it, Bilder dürfen maximal 5MB groß sein. Für Blogs oder Websites die viele Bilder verwenden empfiehlt es sich die Optimierung der Bilder am eigenen PC durchzuführen. Für Windows gibt es den Caesium Image Compressor der ganze Ordner inklusive Unterordner an Bildern optimieren kann. Das Tool ist kostenlos und bietet eine Fülle an möglichen Einstellungen. Apple User haben mit ImageOptim eine recht gute Alternative.

Für die Optimierung der Bilder am eigenen PC empfiehlt es sich alle Bilder aus dem wp-uploads Ordner herunterzuladen und diese anschließend am PC zu optimieren. Die verbesserten Bilder können anschließend direkt wieder hochgeladen werden. Mit einem installierten Image Optimizer Plugin wie reSmush.it werden anschließend alle hochgeladenen Bilder automatisch verbessert. Weitere arbeiten sind in den meisten Fällen nicht mehr notwendig.

Serverantwortzeiten reduzieren (TTFB)

TTFB steht für Time To First Byte und gibt an wie lange ein Besucher auf die Übertragung der ersten Informationen vom Server warten muss. Eine Website die mit PHP programmiert wurde gibt erst Informationen an den Besucher ab nachdem die Ausführung der Scripts vom Server abgeschlossen wurde.. Bei komplexen Websites mit vielen Datenbankabfragen kann dieser Vorgang viel Zeit in Anspruch nehmen, einfache Blogs haben hier also bereits einen merklichen Vorteil. Durch den Einsatz von Caching sollte dieser Wert bereits merklich reduziert worden sein, sollte es auch nach allen Optimierungen noch Probleme mit der Serverantwortzeit geben, liegt dies möglicherweise am Server auf dem eure WordPress Seite gehostet wird. Google selbst empfiehlt Auslieferungen unter 0.2 Sekunden oder 200ms. Speziell bei normalen Webspace Hosting ist man am Hosting Server einer von vielen Kunden die Inhalte ausliefern möchten. Shared Hosting Server können schnell ausgelastet sein, was wiederrum natürlich auch die performance eurer Seite beeinträchtigt. Schlagen alle anderen Optimierungen fehl, hilft oft nur noch der Umzug zu einem anderen Anbieter oder einem eigenen kleinen vServer.

vServer Empfehlung

In Sachen vServer habe ich sehr gute Erfahrungen mit DigitalOcean gemacht. Der Vorteil von Digital Ocean ist, dass man sogenannte Droplets, also praktisch kleine vServer nach Laufzeit bezahlt. Das kleinste Droplet kommt monatlich auf 5 Euro und kann jederzeit gekündigt oder per upgrade verbessert werden. Hat man auf seinem Blog oder seiner Website also plötzlich mehr Zugriffe als der aktuelle vServer verträgt, kann per Knopfdruck ein Upgrade durchgeführt werden. Die Preisänderung tritt direkt nach dem Upgrade ein. Über Themen wie eine monatliche Bindung muss man sich also keine Gedanken machen.

Ein vServer stellt euch nicht ein fix fertiges Admin Panel zur Verfügung, stattdessen muss man selbst Hand anlegen. Digital Ocean pflegt hierfür eine sehr detaillierte Knowledgebase die alle wichtigen Schritte zur Konfiguration eines Linux Servers beinhaltet und auch in Sachen Security informiert. Wer bereits mit der Administration seines eigenen PCs Probleme hat muss sich auf eine Steile Lernkurve einstellen. Der Umgang mit Linux und eigenständigen Servern ist aber der nächste logische Schritt für Web Entwickler. Das durch die Administration gelernte Know How macht sich auf lange Sicht bezahlt und hilft dabei das große Ganze etwas besser zu verstehen.

Mehr Informationen zu Digital Ocean findet Ihr hier (Affiliate Link). Solltet Ihr euch über diesen Link einen Account bei Digital Ocean zulegen, bekommt Ihr ein Guthaben von 100 US-Dollar für einen Zeitraum von 60 Tagen geschenkt. Wenn Ihr euch nach diesem Testzeitraum für Digital Ocean entscheidet und euer Konto aufladet bekomme ich einen kleinen „Kickback“ auf mein Digital Ocean Konto gutgeschrieben. Für euch Fallen dadurch keine höheren kosten an.

Webspace Empfehlungen

Wer den Sprung zu einem eigenen vServer nicht wagen möchte, kann natürlich auch den Webspace Anbieter wechseln. Für Seiten die in Österreich gehostet werden sollen, kann ich Easyname empfehlen. Das Admin Panel ist gut aufgebaut und bietet alle Einstellungsmöglichkeiten die für den Betrieb von WordPress benötigt werden. Aktuelle PHP Versionen sind immer recht zeitnah verfügbar, es gibt kostenlose Zertifikate von LetsEncrypt und einen eigenen Backup Space. Ein SSH Zugang ist bei ein paar Paketen auch dabei, leider aber ohne Root-Rechte.

Weitere Highlights:

  • Varnish / Memcached Server Zugang
  • Cloudflage Integration
  • PHP Einstellungen pro Domain einstellbar
  • CronjobsGuter
  • Preis für gebotene Leistung
  • Bislang immer schnelle Serverantwortzeiten

Alternative: CDN

Ein CDN (Content Delivery Network) entlastet den eigenen Server indem statische Inhalte wie z.B. Bilder über andere gut angebunde Server ausgeliefert werden. Einer der bekanntesten Vertreter dieser Kategorie ist Cloudflare. Ein Content Deliery Network macht speziell bei international ausgerichteten Websites Sinn. Wer bereits einen eigenständigen Server in Verwendung hat der langsam an seine Grenzen stößt kann diesen mithilfe von CDNs wie Cloudflare entlasten. 

Schlusswerte und Fazit

Nach allen Optimierungen sind wir mit unserem Blog bei einer Wertung von 93 (zu Beginn 62) angekommen. Damit sind wir im oberen Bereich angekommen. Ein paar Optimierungen habe ich absichtlich nicht durchgeführt. Zum Beispiel wurde der Stylesheet nicht aufgeteilt oder in den Footer Bereich der Seite verlegt. Mit dieser Optimierung wäre der Wert wohl irgendwo bei 95 bis 97 Punkten angekommen. Der Arbeitsaufwand war einfach zu hoch als das er für einen Blog im Archiv-Modus gerechtfertigt hätte werden können. In meinem Fall war der verwendete Webspace auch schnell genug und rechtfertigte somit nicht die Umstellung auf einen eigenständigen vServer.

Schnelle Websites machen Spaß und schaffen vertrauen. Besonders wichtig sind schnelle Ladezeiten wenn man Produkte oder Dienstleistungen anbietet. Speziell bei Online Shops wirkt sich die Optimierung der Ladezeiten direkt positiv auf die Conversion Rate aus. Ein weiterer netter Nebeneffekt sind die leicht verbesserten Reihungen in den Suchergebnissen, speziell für mobile Geräte. Kurze Ladezeiten sind im Jahr 2019 ein wichtiger Aspekt der keinesfalls außer acht gelassen werden sollte, oder surft Ihr gerne auf langsamen Seiten im Internet?

Sollten Sie Hilfe bei der PageSpeed Optimierung Ihrer Website oder Ihres Online Shops benötigen, helfe ich gerne weiter. Mehr dazu finden Sie z.B. auf der Unterseite – Suchmaschinenoptimierung in Wien und Niederösterreich.

Spambot Bekämpfung ohne Captcha Abfrage

Kontaktformulare sind ein guter Weg Besucher der eigenen Website oder des eigenen Blogs die Möglichkeit zu geben Kontakt aufzunehmen. Seit jeher sind aber auch Bots daran interessiert unerwünschte Werbung über diese Kanäle abzuschicken. Der große Vorteil von Kontaktformularen ist für Spammer, dass die aus dem Formular resultierende Mail mit großer Wahrscheinlichkeit auch wirklich gelesen wird. Mittlerweile gibt es diverse Lösungsansätze um Bots davon abzuhalten, Formulare auf der eigenen Website ausfüllen zu können. Eine der bekannteren Lösungen ist z.B. eine Sicherheitsfrage oder Google’s reCaptcha das dem Nutzer von Zeit zu Zeit Bilderrätsel zeigt die ausgefüllt werden wollen. Beide Lösungen sind für echte Website Besucher nicht optimal und können schnell zu einem Störfaktor werden. Im Fall von reCaptcha spielt auch das Thema Datenschutz eine Rolle. Die Daten die Google aus dem Formular erhebt sind aus technischer Sicht zwar nur auf das Captcha beschränkt, ganz ohne Bauchweh bleibt die Verwendung aber trotzdem nicht. Man sollte davon ausgehen, dass Google Userdaten wie die IP-Adresse, das Nutzerverhalten sowie Browserdetails aufzeichnet. Ohne passenden Datenschutzhinweis kann die Verwendung also problematisch werden. Abseits von Captcha’s und Sicherheitsfragen gibt es aber noch weitere Möglichkeiten Bots erfolgreich auszusperren.

Was machen Spambots eigentlich?

Bevor wir an die Lösungsansätze ansehen, zuerst ein paar interessante Informationen über die Funktionsweise der meisten Bots. Bei Bots handelt es sich im Grunde um Scripts die automatisiert das Internet nach Websites durchsuchen und auf eben diesen Zielgerichtet auf die Suche nach Formularen, E-Mail Adressen sowie anderen Informationen gehen. Dabei springt der Spambot von Seite zu Seite indem er die Links auf der Seite weiterverfolgt. Der Google Spider macht im Grunde nichts anderes, er besucht eine Seite, analysiert den Inhalt, sendet Informationen an die Google Server und springt anschließend von Seite zu Seite. Der große Unterschied zwischen Bots von z.B. Google und Spammern, ist das Verhalten im Bezug auf Formulare. Google Bots füllen keine Formulare aus, Spambots lieben Formulare.

Vorteile von Spambots 

Spambots sind auf Geschwindigkeit getrimmt und versuchen gleichzeitig so wenig Ressourcen wie möglich zu Verbrauchen. Für Spammer gilt Masse statt Klasse und Zeit ist Geld. Der Betrieb eines Spamservers kostet Geld und die abgesendeten Spams haben in den meisten Fällen nur wenig Erfolgschancen. Ziel ist es also so viele Spamnachrichten wie möglich abzuschicken. Pro Server laufen gleichzeitig eine Vielzahl an Bot-Instanzen die gleichzeitig das Internet durchstöbern. Um mehr Bots pro Server ausführen zu können, nutzen Bots einfache Anfragen die an Webserver geschickt werden. Der zurückgegebene HTML Code wird anschließend analysiert. Mitgelieferter CSS oder JavaScript Code wird meist nicht interpretiert um Ressourcen und Zeit zu sparen.

Ansätze zur Spambot Bekämpfung

Wir wissen also ungefähr wie Spambots funktionieren und welche Ziele die Bots verfolgen. Ein Bot der auf die eigene Website kommt, durchforstet alle Unterseiten, stoppt bei jedem gefundenen Formular und versucht dieses auszufüllen und abzuschicken. Wir können davon ausgehen, dass ein großteils der Bots dabei Dinge wie CSS und JavaScript ignorieren. Dieser Umstand, der auch als Vorteil von Spambots interpretiert werden kann, kann zu unserem Vorteil genutzt werden.

Honeypots

Als Honeypot bezeichnet man einen Bereich der eigenen Website die für normale Besucher unsichtbar bzw. unkenntlich gemacht werden. In unserem Fall werden wir einen Honeypot in Form eines Eingabefelds in unser Formular einbauen. Per CSS oder auf Wunsch auch per JavaScript wird dieses Feld anschließend ausgeblendet. Spambots die unsere Seite besuchen und das Kontaktformular finden, sehen den Honeypot als normales Eingabefeld und sind verleitet diesen Auszufüllen. Bei der Verarbeitung des Formulars reicht anschließend eine kurze Abfrage ob das Honeypot Eingabefeld ausgefüllt wurde um mit ziemlicher Sicherheit davon ausgehen zu können, dass die Anfrage von einem Roboter abgeschickt wurde.

Timestamps

Ein normaler Besucher benötigt eine minimale bzw. maximale Zeit um ein Kontaktformular oder Kommentar-Formular auszufüllen. Man kann ohne weiteres davon ausgehen, dass mindestens 10 Sekunden zwischen dem Besuch der Seite und dem abschicken des Formulars vergehen. Bots können diese Arbeit in wenigen Sekunden erledigen. Wir müssen also nur herausfinden wie viel Zeit zwischen dem Seitenaufbau und dem abschicken des Formulars vergangen ist um mögliche Bots zu identifizieren.

Bots die unsere Seite besuchen und Formulare abschicken möchten, müssen mit diesen Änderungen zuerst an dem Honeypot-Feld vorbei und das ausgefüllte Formular anschließend zum richtigen Zeitpunkt abschicken.

Umsetzung mit PHP, HTML und CSS

Werfen wir zuerst einen Blick auf unser HTML Formular mit passenden Hintergrundinfos zu den jeweiligen Feldern.

				
					    <form action="contact.php" method="POST">
      <!-- # Felder die durch User ausgefüllt werden -->
      <div class="formfield">
        <label for="name">Name:</label>
        <input type="text" name="name">
      </div>
      <div class="formfield">
        <label for="email">E-Mail:</label>
        <input type="email" name="email">
      </div>
      <div class="formfield">
        <label for="message">Ihre Nachricht</label>
        <textarea name="message"></textarea>
      </div>


      <!-- Sicherheitsfelder
        Im Nonce Feld wird ein zuvor erstellter "Fingerabdruck" abgespeichert
        der später im Actions Controller geprüft wird. Die Nonce auch CSRF oder
        anders genannt wird benötigt um Cross Scripting Angriffe zu erschweren.
        CMS Systeme wie WordPress oder Frameworks wie Laravel haben passende Funktionen
        zur Einbindung dieser Felder sowie zur Überprüfung. In diesem Beispielt dient das Feld
        nur um euch darauf aufmerksam zu machen diese Funktionen unbedingt zu verwenden.
      -->
        <input type="hidden" name="nonce" value="publicsecret1">


      <!-- Honeypot Feld
        Spam Bots suchen in Formularfeldern nach bekannten Bezeichnungen um einzelne Felder
        voneinander unterscheiden zu können. So gut wie jeder Bot kann dabei zwischen
        den verschiedenen Arten an Textfeldern unterscheiden. Ist ein Textfeld als hidden
        markiert werden sie von Bots ignoriert. Aus diesem Grund erhält unser Honeypot Feld
        per CSS den Wert "display:none;". Dies verhindert das der Browser dem Besucher das Feld
        anzeigt, einfache Bots gehen davon aus, dass das Feld sichtbar ist. Zusätzlich erhält
        das Feld den ansprechenden Namen "subject". Sollte unser "subject" Feld bei der späteren
        Prüfung ausgefüllt sein, können wir die Anfrage direkt blockieren.

        Nachtrag: Ausgefeiltere Bots können über CSS ausgeblendete Elemente erkennen und
        uns nicht in die Falle gehen.
      -->
      <input type="text" class="noeyes" name="subject" value="">


      <!-- Timer Feld
        Für Spammer ist Zeit Geld. Ein Bot hält sich auf jeder Seite also nicht lange
        auf bevor er zur nächsten Seite weiterspringt. Die benötigten Informationen
        werden abgerufen und sofern sich ein Kontaktformular oder ein anderes Ziel
        auf einer Seite befindet, wird dieses angegriffen.
        Die Zeit die ein Bot benötigt um ein Formular auszufüllen liegt oft unter einer Sekunde.
        Diesen Umstand können wir zu unserem Vorteil nutzen. Im Timer Feld platzieren wir
        einen kodierten Timestamp der bei der Abfrage der Seite generiert wird.
        Während der Validierung des Formulars prüfen wir den Timer um zu sehen wie schnell das
        Formular ausgefüllt und abgeschickt wurde. Formulare die in weniger als 5 Sekunden
        ausgefüllt und abgeschickt wurden können wir anschließend mit ziemlicher Sicherheit blockieren.

      -->
      <input type="text" class="noeyes" name="phone" value="<?php echo generateTimeHash($key, $cipher, $iv); ?>">

      <input type="submit" value="Absenden">

    </form>
				
			

Im Beispiel haben wir zuerst unsere normalen Eingabefelder für Name, E-Mail, und die Nachricht die abgeschickt werden soll. Anschließend habe ich zu Demo-Zwecken ein sogenanntes Nonce-Feld eingebaut. Die „Nonce“ soll Cross-Site-Request-Forgery Angriffe abwehren und sollte in jedem Formular auf eurer Seite genutzt werden. Praktisch alle CMS-Systeme sowie Frameworks bieten diese Funktion und sollten auf jeden Fall genutzt werden. In der Demo sind die Felder zwar eingetragen aber nicht mit Funktionen versehen.

Interessant wird das Form-Feld beim nächsten Input-Feld mit dem Namen „subject“. Bei diesem Feld handelt es sich um unser Honeypot Feld. Der Name des Formfelds ist so gewählt, dass er für mögliche Bots als Betreff-Feld registriert und passend ausgefüllt wird. Per CSS wird das Formfeld ausgeblendet und ist somit für normale Besucher nicht sichtbar. Wir blenden das Feld per CSS aus, da Bots Formfelder vom Typ „hidden“ ignorieren würden.

Nach unserem Honeypot-Feld findet sich unser Timer. Im Timer Feld platzieren wir eine verschlüsselte Timestamp die bei der Erstellung der Seite per PHP generiert und eingefügt wird. Dieses Feld blenden wir auch per CSS aus und geben ihm einen für Bots interessanten Namen um Änderungen an dem Feld zu provozieren. In unserer contact.php Datei die Anfragen verarbeitet wird dieses Feld anschließend entschlüsselt und geprüft. Natürlich prüfen wir bei der Gelegenheit auch gleich, ob ein Bot Änderungen an dem Feld vorgenommen hat.

Nachfolgend die Funktion die für die Erstellung des verschlüsselten Timestamps zuständig ist.

				
					// der Key mit dem wir unser timer feld verschlüsseln
$key = 'MySecretHashkey876574';

// zweiter unique key für die verschlüsselung und entschlüsselung des timehash
$iv = '0259847523614897';

// die verschlüsselungsmethode
$cipher = 'aes-128-cbc';


// erstellt verschlüsseltes timestamp feld
function generateTimeHash($key, $cipher, $iv) {

  // erstelle aktuellen timestamp
  $time = new DateTime();

  // teste ob verschlüsselungsmethode vorhanden ist oder stirb
  if(in_array($cipher, openssl_get_cipher_methods())) {

    // gibt verschlüsselten timestamp wert zurück
    return openssl_encrypt($time->getTimestamp(), $cipher, $key, 0, $iv);

  }

  die('Verschlüsselungsmethode nicht gefunden oder Fehler bei Verschlüsselung');

}
				
			

Für die Verschlüsselung des Timestamp Felds nutzen wir die PHP-Funktion openssl_encrypt. Dieser übergeben wir den aktuellen Timestamp, die Verschlüsselungsmethode, einen Schlüssel sowie einen Initialisierungsvektor. Die Funktion testet auch ob die gewählte Verschlüsselungsmethode verfügbar ist und beendet das Script falls dem nicht der Fall ist. Das Timestamp Feld sieht im fertigen Formular anschließend wie folgt aus.

Kommen wir zur contact.php in der wir die erhaltene Anfrage bearbeiten. Starten wir mit unserem Honeypot-Feld. Wie zuvor beschrieben muss dieses Feld leer sein, falls es ausgefüllt ist, handelt es sich bei der Anfrage höchstwahrscheinlich um einen Bot. Wir testen ob die POST Variable vorhanden ist und ob sie wie erwartet ein leerer String ist. In der Demo beenden wir die Ausführung sofern das subject Feld nicht übergeben wurde.

				
					$honeypot = isset($_POST['subject']) ? $_POST['subject'] : die('Betreff Feld gelöscht');


/*
  Wenn das Honeypot Feld nicht leer ist, gehen wir davon aus das uns ein Bot
  in die Falle gegangen ist.
*/
if(!empty($honeypot)) {
  $failmessage = true;
}
				
			

Im nächsten Schritt kümmern wir uns um unsere Timestamp Variable. Diese muss uns übergeben werden und auch erfolgreich entschlüsselt werden können. Sollte die Entschlüsselung nicht funktionieren wurde das Eingabefeld bearbeitet. Dies bedeutet, dass der Bot oder der User auf der anderen Seite unerwünschte Absichten hat. Die Anfrage wird also blockiert. Sollte das Timestamp Feld entschlüsselt werden können vergleichen wir die aktuelle Zeit mit der übergebenen Zeit und ermitteln die vergangenen Sekunden mit unseren minimalen und maximalen Werten.

				
					/* Minimale Zeit in Sekunden die nach der Auslieferung der Seite
  vergehen muss um nicht im Botfilter zu landen
*/
$minTime = 5;

/* Maximale Zeit in Sekunden die während des ausfüllens des Formulars verstreichen darf
  manche bots befüllen das Formular und senden es zu einem späteren Zeitpunkt ab um diese
  Art der Sicherheitschecks zu umgehen.
*/
$maxTime = 3600;

$givenTime = isset($_POST['phone']) ? $_POST['phone'] : die('Timestamp Feld gelöscht');

// dekodiere übergebenen Timestamp
$decryptedTime = openssl_decrypt($givenTime, $cipher, $key, 0, $iv);

// überprüfe ob der übergeben wert überprüft werden konnte
if($decryptedTime) {

  // erstelle aktuellen timestamp
  $currentTime = new DateTime();
  $currentTime = $currentTime->getTimestamp();

  /*
    Jetzt berechnen wir die Sekunden die der User für das Ausfüllen des Formulars
    benötigt hat. Sollte der Wert kleiner als unser Threshold sein, blockieren wir
    die Anfrage.
  */
  if( ($currentTime - $decryptedTime) <= $minTime || ($currentTime - $decryptedTime) >= $maxTime ) {
    $failmessage = true;
    $timeError = 'Minimale Zeit für Ausfüllung unterschritten / überschritten';
  }

} else {
  // gelieferter Wert konnte nicht decypted werden -> Eingabefeld wurde bearbeitet
  $failmessage = true;
  $timeError = 'Verschlüsselter Zeit-String wurde bearbeitet';
}
				
			

Sollte die $failmessage Variable nach der Ausführung True sein, stehen die Chancen gut, dass die Anfrage von einem Bot ausgegangen ist. Die Variable $honeypot beinhaltet den Text der in unser Honeypot Feld eingegeben wurde, oder ist leer wenn die Variable nicht ausgefüllt wurde. Die Variable $timeError wird auf true gesetzt wenn es ein Problem bei der Entschlüsselung der übergebenen Daten gegeben hat, oder wenn die vergangene Zeit nicht die Schwellenwerte erreicht, oder diese überschritten hat. Zum Abschluss noch die Ausgabe der contact.php in unserer Demo.

				
					<?php
/*
  In dieser Demo werden die POST Variablen nicht gefiltert und validiert!
*/
$name = $_POST['name'];
$email = $_POST['email'];
$message = $_POST['message'];

?>


<html>
  <head></head>
  <body>
    <p>
      <?php if( $failmessage ) {
        echo '<span style="color:red;font-weight:bold;">Bot Aktivität entdeckt</span>';
      } else {
        echo '<span style="color:green;font-weight:bold;">Keine Bot Aktivität entdeckt</span>';
      }
      ?>
    </p>
    <p>
      Ihr Name: <?php echo $_POST['name']; ?><br>
      Ihre E-Mail: <?php echo $_POST['email'];?><br>
      Ihre Nachricht: <?php echo $_POST['message']; ?>
    </p>
    <p>
    Honeypot: 
    <?php 
    if(!empty($honeypot)) {
      echo '<span style="color:red;font-weight:bold;">ausgefüllt</span><br> ';
      echo 'Eingegebener Text: ' . $honeypot;
    } else {
      echo '<span style="color:green;font-weight:bold;">nicht ausgefüllt</span>';
    } ?>
    <p>
    <p>
      Zeitfeld:
      <?php if( !$timeError ) {
        echo '<span style="color:green;font-weight:bold;">Vergange Zeit in Sekunden:' . ($currentTime - $decryptedTime) . '</span>';
      } else {
        echo '<span style="color:red;font-weight:bold;">' . $timeError . '</span>';
      }?>
    </p>
  </body>
</html>
				
			

Alle Daten aus der Demo die für diesen Beitrag erstellt wurde habe ich in dieser .zip Datei für euch bereitgestellt. Download

Fazit

Einfach gestrickte Bots können mit diesen ersten Maßnahmen schnell ausgesperrt werden. Ein Vorteil dieser Maßnahmen ist, dass echte Besucher nichts von den Maßnahmen zu spüren bekommen. Was in unserer Demo fehlt ist weitere Logik die mögliche Angreifer nach mehreren Versuchen aussperrt. Denkar ist eine zeitliche Sperre oder eine Blacklist. Die rechtlich Tragbarkeit einer Blacklist unter der DSGVO ist leider bedenklich. Möglich ist es auch dem Bot eine erfolgreiche Anfrage vorzugaukeln im Hintergrund aber keine Aktionen auszuführen. Möglich wäre es an dieser Stelle auch dem Bot eine 404 Fehlerseite zu zeigen und ihm vorzugaukeln, dass das Formular ins nichts führt.

Intelligentere Bots die Formulare z.B. zeitversetzt abschicken und auch CSS oder JavaScript auslesen können, werden durch die oben gezeigten Maßnahmen leider wenig beeindruckt. Mögliche weitere Absicherungen wäre z.B. die Nutzung eines einmaligen Tokens der in der Session jedes Besuchers gespeichert und bei der Verarbeitung des Formulars abgefragt und getestet wird. Sollten alle Stricke reißen kann man in letzter Instanz natürlich immer noch eine Sicherheitsabfrage einbauen.

Solltet Ihr weitere Tipps für den Kampf gegen Formular-Spam auf der eigenen Website haben, könnt Ihr diese gerne in den Kommentaren hinterlassen.

Gerne helfe ich auch bei der Umsetzung von Lösungen gegen Spam. Kontaktiert mich, oder erfahrt mehr über meine weiteren Angebote bei der Website Erstellung.

Kontakt
Ihre Daten werden ausschließlich zur Bearbeitung Ihrer Anfrage verarbeitet. Mehr Informationen findest du in unserer Datenschutzerklärung

Bürozeiten:
Montag – Freitag: 9 – 19 Uhr
Samstag: 9 – 16 Uhr

Im Notfall auch am Wochenende erreichbar