Hinweis: Neben den Anleitungen im Rahmen dieser Serie habe ich mittlerweile fertige Shell Scripte erstellt, die quasi voll automatisch die Installation eines Servers für euch übernehmen. Ihr findet das Ganze auf github.de, wobei ihr entweder den ganzen Server per Script aufsetzen und konfigurieren lassen könnt, oder eben jeden einzelnen Schritt, wie  z.B. das Absichern des Servers, oder das Installieren eines LEMP Stacks, mit Hilfe der jeweiligen Scripte erledigen könnt. Die Scripte entsprechen quasi 1:1 zu den Tutorials.

Inhalte

Redis und Co. Cache me if you can!

Es gibt wohl heutzutage nichts nervigeres im Internet, also langsam ladende Websites. Okay, zugegeben, mit Werbung überladende Seiten sind auch kein Hit! Beides führt mitunter dazu, dass die Leute direkt abspringen und stattdessen eine andere Seite aufrufen. Die Ladezeiten eurer Website hängen von einer Vielzahl an Faktoren ab, wovon wir uns heute einen dieser Faktoren mal genauer angucken wollen. Das Caching.

Cache bedeutet nichts anderes, als einen schnellen Zwischenspeicher. Satt also immer und immer wieder neu irgendwelche Dinge zu berechnen, aus einer Datenbank auszulesen, etc. werden die Ergebnisse aller früheren Abfragen local zwischengespeichert, entweder irgendwo auf der Festplatte des Servers, vorzugsweise einer SSD, oder am besten direkt im RAM, je nachdem, welche Methode zum Einsatz kommt.

WordPress z.B. setzt auf PHP. Im Normalfall werden bei jedem Seitenaufruf die Seiten anhand des PHP Codes für den Besucher neu generiert. Wenn es sich dabei jetzt aber nicht um dynamischen Content handelt, wie z.B. ein Video oder dergleichen, reicht es im Prinzip aus, wenn diese Seite ein einziges Mal von eurem Webserver generiert wird. Die fertig generierte Seite wird also zwischengespeichert und steht jedem erneuten Besucher direkt zur Verfügung. Das Spart nicht nur Zeit, sondern auch Ressourcen. Eine dieser Möglichkeiten, dynamische Seiten in Form von statischen Seiten zwischenzuspeichern ist z.B. der fastcgi_cache von nginx. Wie genau dieser für WordPress und Co konfiguriert wird, werden wir uns zu einem späteren Zeitpunkt, im Rahmen der WordPress Installation angucken.

Was wir aber heute machen werden, sind die gängigen, oder zumindest in meinen Augen sinnvollen Caching Methoden, welche auch später in weiteren Tutorials zum Einsatz kommen werden, zu installieren, bzw. zu konfigurieren.

Redis – In-Memory-Datenbank

Bei Redis handelt es sich im eine sog. NoSQL-Datenbank, welche zwar keine komplexen Strukturen wie eben SQL Datenbanken speichern kann, aber dafür wesentlich schneller arbeitet. Ein weiterer Vorteil ist, dass der Redis Server komplett aus dem RAM heraus agiert. Das hat zwar den Nachteil, dass der Cache im Zweifel bei einem ungewollten Neustart des Systems leer ist, sorgt aber auch dafür, dass Anfragen viel schneller beantwortet werden, als beispielsweise von einer SSD oder gar einer HDD.

Auf Grund der Komplexität eignet sich Redis also nicht unbedingt für das Zwischenspeichern kompletter Websites, sondern eher als Object Cache, für einzelne Anfragen. Wir werden Redis aus diesem Grund hauptsächlich nutzen, um Datenbankabfragen zu cachen. Statt also immer und immer wieder Werte aus der SQL Datenbank abzurufen, werden diese mit Hilfe von Redis zwischengespeichert, wobei Redis über keine frei definierbaren Datenbanken wie z.b. MySQL verfügt, sondern lediglich numerische Datenbanken, d.h. mit den Namen 0, 1, 2 … etc. besitzt. Für den Fall, dass man mehrer Datenbanken simultan auf einem Server verwendet, sollte man sich also evtl. irgendwo Notizen dazu machen, welche Datenbank welche Werte zwischenspeichert.

Installation

Wie so oft gibt es auch bei der Installation des Redis Servers verschieden Möglichkeiten. Wir werden im Rahmen des Tutorials allerdings nur die manuelle Installation mit Hilfe der Source Files durchgehen da diese im Gegensatz zu allen anderen Optionen immer die aktuellste Version beinhalten.

Zunächst laden wir hierfür die passenden files herunter, entpacken sie und compilieren, bzw. installieren anschließend den Redis-Server.

Auf den „PREFIX=/usr“ kann theoretisch auch verzichtet werden, die Redis files werden dann statt im Ordner /usr/bin, unter /usr/local/bin abgelegt. Achtet nur am Ende bei der Konfiguration darauf, welchen Pfad ihr gewählt habt.

wget http://download.redis.io/redis-stable.tar.gz 
tar -xzf redis-stable.tar.gz
cd redis-stable
make 
make PREFIX=/usr install 
cd ..

Die „Installation“ in diesem Sinne ist nun eigentlich fertig, allerdings benötigen wir für die anschließende Konfiguration noch einige Ordner, bzw. Rechte. Da es unklug wäre, den Redis-Server unter dem root user laufen zu lassen, da sonst kein anderer Systembenutzer, wie z.B. www-data später Zugriff darauf hätte, legen wir zusätzlich einen neuen Benutzer, bzw. eine neue Gruppe an, zu der wir auch direkt www-data als Nutzer hinzufügen.

adduser --system --group --no-create-home redis 
usermod -g www-data redis
mkdir /etc/redis 
mkdir /var/lib/redis 
mkdir /var/log/redis 
touch /var/log/redis/redis.log
chown -R redis:redis /etc/redis
chown -R redis:redis /var/lib/redis
chown -R redis:redis /var/log/redis

Für die spätere Kommunikation mit php, installieren wir an dieser Stelle gleich schon mal die Erweiterung php-redis.

apt-get install -y php-redis

Konfiguration

Kommen wir nun zur Konfiguration unseres Redis Servers. Hier haben wir zwei Möglichkeiten, Redis kann entweder per TCP Port erreichbar sein, oder aber per UNIX Socket. Beides Zusammen ist eher weniger Sinnvoll.

Da die Kommunikation via UNIX Socket in der Regel etwas schneller läuft, also übe den  TCP Port, ist dieser in meinen Augen immer die bessere Wahl, auch weil der Socket nicht von Außen erreichbar ist und das ganze System somit in sich geschlossen ist. Für den Fall, dass ihr aber lieber den TCP Port verwenden möchtet, weil ihr z.B. Redis auf einem extra Server laufen lassen wollt, werde ich beide Konfigurationen kurz erklären.

Option 1: UNIX Socket

Wir könnten zwar auch das automatische Konfigurations-Script benutzen, erstellen die Config aber lieber von Hand. Hierzu kopieren wir die Beispiel-Config in unser zuvor erstelles redis Verzeichnis.

cp redis-stable/redis.conf /etc/redis/redis.conf

Diese Config können wir nun manuell editieren, oder aber eben wie bereits in zurückliegenden Tutorials, mit Hilfe von sed.

sed -i 's/^logfile .*/'"logfile \/var\/log\/redis\/redis.log/g" /etc/redis/redis.conf
sed -i 's/^dir .*/'"dir \/var\/lib\/redis/g" /etc/redis/redis.conf
sed -i 's/^pidfile .*/'"pidfile \/var\/run\/redis\/redis-server.pid/g" /etc/redis/redis.conf
sed -i 's/^port .*/'"port 0/g" /etc/redis/redis.conf
sed -i 's/^# unixsocket .*/'"unixsocket \/var\/run\/redis\/redis.sock/g" /etc/redis/redis.conf
sed -i 's/^# unixsocketperm .*/'"unixsocketperm 770/g" /etc/redis/redis.conf
sed -i 's/^daemonize .*/'"daemonize yes/g" /etc/redis/redis.conf

Option 2: TCP Port

Die Konfiguration läuft ähnlich ab. Wir kopieren zunächst die config und editieren sie.

cp redis-stable/redis.conf /etc/redis/redis.conf
sed -i 's/^logfile .*/'"logfile \/var\/log\/redis\/redis.log/g" /etc/redis/redis.conf
sed -i 's/^dir .*/'"dir \/var\/lib\/redis/g" /etc/redis/redis.conf
sed -i 's/^pidfile .*/'"pidfile \/var\/run\/redis\/redis-server.pid/g" /etc/redis/redis.conf
sed -i 's/^port .*/'"port 6379/g" /etc/redis/redis.conf
sed -i 's/^daemonize .*/'"daemonize yes/g" /etc/redis/redis.conf

Da unser Redis Server nun aber via TCP Port online erreichbar ist, also ein potentielles Angriffsziel, benötigen wir noch ein sicheres Passwort. Dieses generiere ich automatisch und füge es der Config hinzu.

redis_secure=$(date +%s | sha256sum | base64 | head -c 32; echo)
sed -i 's/^# requirepass .*/'"requirepass $redis_secure/g" /etc/redis/redis.conf
echo "Dein Redis Passwort: $redis_secure"

Die Ausgabe „Dein Redis Passwort: ….“ solltest du dir am besten irgendwo notieren, da du das Passwort später immer wieder benötigst, um mit deinem Redis Server zu kommunizieren.

Hinweis: Solltest du vergessen haben das Passwort zu notieren, kannst du es auch einfach jeder zeit in der /etc/redis/redis.conf unter „requirepass“ nachlesen können.

Systemstart

Damit Redis auch nach einem Reboot wieder startet, bzw. um den Redis Server komfortabler zu administrieren, benötigen wir noch ein passendes Service script.

cat > /lib/systemd/system/redis.service <<EOF
[Unit]
Description=Advanced key-value store
After=network.target
Documentation=http://redis.io/documentation, man:redis-server(1)

[Service]
Type=forking
ExecStart=/usr/bin/redis-server /etc/redis/$redis_conf
ExecStop=/bin/kill -s TERM \$MAINPID
PIDFile=/var/run/redis/redis-server.pid
TimeoutStopSec=0
Restart=always
User=redis
Group=www-data
RuntimeDirectory=redis
RuntimeDirectoryMode=2755

UMask=007
PrivateTmp=yes
LimitNOFILE=65535
PrivateDevices=yes
ProtectHome=yes
ReadOnlyDirectories=/
ReadWriteDirectories=-/var/lib/redis
ReadWriteDirectories=-/var/log/redis
ReadWriteDirectories=-/var/run/redis

NoNewPrivileges=true
CapabilityBoundingSet=CAP_SETGID CAP_SETUID CAP_SYS_RESOURCE
MemoryDenyWriteExecute=true
ProtectKernelModules=true
ProtectKernelTunables=true
ProtectControlGroups=true
RestrictRealtime=true
RestrictNamespaces=true
RestrictAddressFamilies=AF_INET AF_INET6 AF_UNIX

# redis-server can write to its own config file when in cluster mode so we
# permit writing there by default. If you are not using this feature, it is
# recommended that you replace the following lines with "ProtectSystem=full".

ProtectSystem=true
ReadWriteDirectories=-/etc/redis

[Install]
WantedBy=multi-user.target
Alias=redis.service
EOF

Anschließend sorgen wir dafür, dass der Server das Script auch findet und aktivieren Redis beim Systemstart.

ln -s /lib/systemd/system/redis.service /etc/systemd/system/redis.service

systemctl daemon-reload 
systemctl start redis 
systemctl enable redis

So, das wars auch schon. Nun sollte Redis eigentlich ohne Probleme auf eurem Server laufen.

Aufräumen nicht vergessen.

rm redis-stable.tar.gz
rm -rf redis-stable

Testen

Falls ihr überprüfen wollt, ob alles funktioniert habt, könnt ihr das mit Hilfe des „redis-cli“ scripts.

redis-cli ping [Redis Server per TCP Port, ohne Passwort]
redis-cli -a <passwort> [Redis Server per TCP Port, mit Passwort]
redis-cli -s /var/run/redis/redis.sock ping [Redis Server per Socket]

In jedem Fall sollte die Antwort „PONG“ lauten.

APCu – APC User Cache

APCu ist quasi der Nachfolger von APC – Alternative PHP Cache. APC fungierte zum einen als PHP-Beschleuniger, indem Bytecode im RAM ausgelagert wurde und zum anderen bot es einzelnen PHP Apps die Möglichkeit selbst Daten zu cachen. Die Aufgaben des PHP-Beschleunigers übernimmt mittlerweile OPcache, welches von Haus aus mit PHP zusammen ausgeliefert wird und das Cachen übernimmt nun eben APCu. Aufwendige Datenbankabfragen lassen sich z.B. mit APCu in den Zwischenspeicher legen, was wertvolle Zeit einspart.

Installation

APCu wird leider aktuell nicht als Modul für php7.2 per apt angeboten, weswegen wir es ebenfalls, wie Redis, aus dem Source compilieren.

git clone https://github.com/krakjoe/apcu 
cd apcu
phpize 
./configure 
make 
make install

Aufräumen nicht vergessen.

rm -rf apcu

Eine weitere Möglichkeit wäre die Installation via PECL.

apt-get install -y php-pear
pecl install apcu

Bitte aber nur auf einem Weg installieren!

Konfiguration

Die Konfiguration erledigen wir wieder schnell mit Hilfe von sed via Console. Nicht vergessen php-fpm anschliend neuzustarten.

echo "extension = apcu.so" | tee -a /etc/php7.2/mods-available/apcu.ini 
ln -s /etc/php7.2/mods-available/apcu.ini /etc/php7.2/fpm/conf.d/30-apcu.ini
ln -s /etc/php7.2/mods-available/apcu.ini /etc/php7.2/cli/conf.d/30-apcu.ini
ln -s /etc/php7.2/mods-available/apcu_bc.ini /etc/php7.2/fpm/conf.d/30apcu_bc.ini
ln -s /etc/php7.2/mods-available/apcu_bc.ini /etc/php7.2/cli/conf.d/30apcu_bc.ini

service php7.2-fpm restart

Um zu überprüfen, ob alles funktioniert habt, könnt ihr den Befehl php -m benutzen. Der Output sollte in etwas so aussehen, wobei der Eintrag APCu relevant ist.

root@xf0:~# php -m
[PHP Modules]
apcu
bcmath
bz2
calendar
Core
ctype
curl
date
dom
exif
fileinfo
filter
ftp
gd
gettext
hash
iconv
igbinary
intl
json
libxml
mbstring
mysqli
mysqlnd
openssl
pcntl
pcre
PDO
pdo_mysql
Phar
posix
readline
redis
Reflection
session
shmop
SimpleXML
sockets
sodium
SPL
standard
sysvmsg
sysvsem
sysvshm
tokenizer
wddx
xml
xmlreader
xmlwriter
xsl
Zend OPcache
zip
zlib

[Zend Modules]
Zend OPcache

OPcache – On Board Bescheleunier

Wie bereits im vorherigen Schritt erklärt, ist OPcache fester Bestandteil von PHP und fungiert als Beschleuniger. Klingt erst mal ganz gut, ne? Leider aber wird OPcache weder von Haus aus aktiviert, noch konfiguriert.  Beides lässt sich aber mit wenigen Handgriffen, bzw. einem copy&paste Befehl beheben.

cat >> /etc/php/php7.2/fpm/conf.d/10-opcache.ini <<EOF

opcache.enable=1
opcache.enable_cli=1
opcache.interned_strings_buffer=8
opcache.max_accelerated_files=10000
opcache.memory_consumption=128
opcache.save_comments=1
opcache.revalidate_freq=1
EOF

service php7.2-fpm restart

 

So, damit wären wir auch schon durch. Ihr habt nun 3, bzw. wenn man fastcgi_cache aus dem LEMP Tutorial hinzuzählt, 4 Cache Möglichkeiten, welche sich für unterschiedliche Einsatzzwecke eignen.

Kommentieren Sie den Artikel

Please enter your comment!
Please enter your name here