Webserver mit Nginx, PHP7 & MariaDB
31.12.2019Hinweis: Ihr benötigt für viele oder alle Schritte dieser Anleitung einen User mit sudo Rechten oder den root User. Ich nutze den root User, tut ihr dies nicht, müsst ihr bei den angegebenen Befehlen "sudo" voranstellen, z.B. "sudo apt update".
Sprungmarken: PHP 7.3 Certbot Nginx MariaDB phpMyAdmin
Server Update
Bevor ihr mit der eigentlichen Anleitung beginnt, solltet ihr vorab den Server updaten!
apt update && apt dist-upgrade && apt autoremove && apt clean
Mit dieser Befehls-Kombination aktualisiert ihr die Paketquellen, sucht nach Upgrades für installierte Pakete, entfernt überflüssige Abhängigkeiten und leert den Paket-Cache. "dist-upgrade" hat gegenüber "upgrade" den Vorteil, dass zusätzlich geprüft wird, ob durch geänderte Abhängigkeiten bestimmte Pakete deinstalliert bzw. neu installiert werden sollten.
PHP 7.3
Ihr solltet zuerst PHP (php-fpm) installieren, damit ihr dieses bei der Nginx Konfiguration sofort mit einbeziehen könnt. Außerdem solltet ihr, sofern ihr MariaDB nutzen werdet, auch das php-mysql Paket installieren, damit PHP Scripte auf die Datenbank zugreifen können. Installieren könnt ihr die Pakete mit folgendem Befehl.
apt install -y php7.3-fpm php7.3-mysql
Damit habt ihr PHP erfolgreich installiert und könnt mit dem nächsten Schritt weitermachen. Man kann zwar PHP-FPM über die Konfiguration noch optimieren, das ist aber etwas aufwendiger und von eurer Hardware abhängig, da gibt es meiner Meinung nach keine pauschal sinnvollen Angaben (auch wenn manche Guides im Internet das anders darstellen). Für wenig bis mittel gut besuchte Webseiten sollte die Standardkonfiguration aber sowieso ausreichen. Eine falsche Konfiguration kann zudem zu großen Problemen, wie einem voll laufenden RAM, führen.
Ältere PHP Versionen: Es ist auch problemlos möglich, eine ältere Version bzw. mehrere Versionen gleichzeitig zu installieren. Das kann beispielsweise nötig sein, wenn ihr zwei Webseiten bzw. Anwendungen auf dem Server betreiben wollt, eine davon PHP 7.3 unterstützt, die andere aber nur PHP 7.1. Im Debian 10 Repository (stable) werdet ihr nur die aktuelle Version (zur Zeit 7.3) bekommen. Daher müsst ihr, um eine ältere Version zu installieren, erst das Repository "deb.sury.org" von Ondrej Sury (Hauptentwickler der PHP Pakete unter Debian) einpflegen.
apt install -y apt-transport-https lsb-release ca-certificates
wget -O /etc/apt/trusted.gpg.d/php.gpg https://packages.sury.org/php/apt.gpg
echo "deb https://packages.sury.org/php/ buster main" > /etc/apt/sources.list.d/php.list
apt update
Anschließend könnt ihr ganz einfach die gewünschte Version installieren, beispielsweise für PHP7.1 wie folgt.
apt install -y php7.1-fpm
Certbot (Lets Encrypt)
Als nächstes solltet ihr Cerbot installieren, um kostenlose TLS Zertifikate von Lets Encrypt beantragen zu können. Heutzutage sollte eigentlich jede Webseite über https aufgerufen werden können, auch wegen entsprechender Warnmeldungen bei aktuellen Browsern. Außerdem solltet ihr noch das Nginx Plugin mitinstallieren, damit ihr direkt über Nginx Zertifikate beantragen und später erneuern könnt.
apt install -y certbot python-certbot-nginx
Anschließend könnt ihr direkt ein TLS Zertifikat für eure Domain/Subdomain beantragen.
certbot certonly --rsa-key-size 4096 -d domain.tld -d www.domain.tld --nginx
Wenn ihr das erste Mal ein Zertifikat beantragt, müsst ihr eine E-Mail Adresse angeben, den ToS zustimmen und Entscheiden ob ihr die E-Mail Adresse mit Partnern von Lets Encrypt teilen wollt (N für ablehnen).
Abschließend solltet ihr noch dafür sorgen, dass eure Zertifikate automatisch erneuert werden, da diese nur 3 Monate gültig sind. Dafür könnt ihr bequem einen Cronjob anlegen, der fortan jeden Monat eure Zertifikate erneuert.
nano /etc/crontab
In dieser Datei ergänzt ihr dann ganz unten den folgenden Cron.
0 4 1 * * root certbot renew --force-renew --nginx
Das war es auch schon, ab sofort werden eure Zertifikate immer am 1. eines Monats um 4 Uhr morgens erneuert.
Nginx
Nun könnt ihr Nginx installieren.
apt install -y nginx
Bevor ihr euch nun an den Konfigurationen zu schaffen macht, fahrt ihr zuerst Nginx runter.
service nginx stop
Nun könnt ihr mit der Konfiguration von Nginx beginnen. Zuerst könnt ihr die unnötigen Dateien in "Snippets" löschen, die wir später sowieso ersetzen. In diesem Ordner werdet ihr später Konfigurationen für verschiedene Dinge anlegen, mit denen ihr die einzelnen Webseiten-Konfigurationen erweitern könnt. Zudem könnt ihr die Verknüpfung der Standard-Seitenkonfiguration löschen.
rm /etc/nginx/snippets/* ; rm /etc/nginx/sites-enabled/*
Optional: Ich persönlich lösche zusätzlich die Ordner "sites-available" und "modules-available" und benenne "modules-enabled" in "modules" und "sites-enabled" in "sites" um. Das ist aber Geschmackssache und eher unüblich. Eigentlich sieht Nginx vor, dass im jeweiligen "-available" Ordner die Konfiguration und im entsprechenden "-enabled" Ordner eine Verknüpfung angelegt wird. So kann man Module und Seiten durch löschen der Verknüpfung an- und abschalten. Ihr könnt das aber natürlich so machen, wenn ihr das möchtet. Alternativ könnt ihr auch einfach die Konfigurationen direkt im jeweiligen "-enabled" Ordner erstellen. Ich bin aber kein Fan von leeren/sinnlosen Ordnern, daher räume ich wie beschrieben immer gerne etwas auf.
rm -R /etc/nginx/modules-available/ ; rm -R /etc/nginx/sites-available/
mv /etc/nginx/modules-enabled /etc/nginx/modules ; mv /etc/nginx/sites-enabled /etc/nginx/sites
Für eine bessere Übersicht, könnt ihr euch den Ordner von Certbot mit den aktiven Zertifikaten im Nginx Ordner verknüpfen. Dies könnt ihr bei der Seitenkonfiguration dann auch als Pfad verwenden.
ln -s /etc/letsencrypt/live/ /etc/nginx/sslcerts
Nun könnt ihr Konfigurationen erstellen. Sinnvollerweise nutzt ihr den Ordner "conf.d" für Konfigurationen die ihr in "nginx.conf" einbinden werdet; also die, die für alle eure Seiten zur Anwendung kommen sollen. Den Ordner "snippets" nutzt ihr hingegen für Konfigurationen, die ihr nur bei bestimmten Seiten anwenden wollt oder die in der globalen Konfiguration nicht zulässig sind, z.B. location{} Blocks wie bei der PHP Konfiguration.
Erstellt zuerst die Konfiguration für PHP7.3 (nutzt ihr eine ältere Version, müsst ihr diese in "fastcgi_pass" ändern!).
nano /etc/nginx/snippets/php_7-3.conf
Von mir empfohlener Inhalt:
location ~ (?U)\.php(/.*$|$) {
fastcgi_split_path_info ^(.+?\.php)(/.*)$;
fastcgi_pass unix:/var/run/php/php7.3-fpm.sock;
fastcgi_index index.php;
fastcgi_keep_conn on;
fastcgi_buffer_size 128k;
fastcgi_buffers 256 16k;
fastcgi_busy_buffers_size 256k;
fastcgi_temp_file_write_size 256k;
fastcgi_read_timeout 240;
fastcgi_intercept_errors on;
try_files $fastcgi_script_name =404;
set $path_info $fastcgi_path_info;
fastcgi_param PATH_INFO $path_info;
include fastcgi.conf;
}
Nun könnt ihr die Browser Cache Konfiguration anlegen.
nano /etc/nginx/snippets/cache.conf
Von mir empfohlener Inhalt:
location ~* \.(ogg|ogv|svg|svgz|eot|otf|woff|woff2|mp4|ttf|rss|atom|jpg|jpeg|gif|png|ico|zip|tgz|gz|rar|bz2|doc|xls|exe|ppt|tar|mid|midi|wav|bmp|rtf)$ {
expires 30d;
add_header Pragma "public";
add_header Cache-Control "public, no-transform";
}
location ~* \.(css|js)$ {
expires 7d;
add_header Pragma "public";
add_header Cache-Control "public, no-transform";
}
Nun könnt ihr die Header Konfiguration anlegen.
nano /etc/nginx/conf.d/headers.conf
Von mir empfohlener Inhalt:
add_header X-Cache $upstream_cache_status;
add_header X-Frame-Options SAMEORIGIN always;
add_header X-Content-Type-Options nosniff;
add_header X-XSS-Protection "1; mode=block" always;
add_header "Cache-Control" "no-transform";
add_header Strict-Transport-Security "max-age=15768000; includeSubDomains" always;
proxy_hide_header Etag;
Nun könnt ihr die SSL Konfiguration anlegen.
nano /etc/nginx/conf.d/ssl.conf
Von mir empfohlener Inhalt:
ssl_prefer_server_ciphers on;
ssl_protocols TLSv1 TLSv1.1 TLSv1.2;
ssl_ciphers EECDH+CHACHA20:EECDH+AES128:RSA+AES128:EECDH+AES256:RSA+AES256:EECDH+3DES:RSA+3DES:!MD5;
ssl_session_cache shared:SSL:5m;
ssl_session_timeout 30m;
Nun könnt ihr die Gzip Konfiguration anlegen.
nano /etc/nginx/conf.d/gzip.conf
Von mir empfohlener Inhalt:
gzip on;
gzip_buffers 32 16k;
gzip_http_version 1.1;
gzip_disable "msie6";
gzip_vary on;
gzip_proxied any;
gzip_proxied expired no-cache no-store private auth;
gzip_comp_level 6;
gzip_min_length 250;
gzip_types
application/atom+xml
application/javascript
application/json
application/ld+json
application/manifest+json
application/rdf+xml
application/rss+xml
application/schema+json
application/vnd.geo+json
application/vnd.ms-fontobject
application/x-font-ttf
application/x-javascript
application/x-web-app-manifest+json
application/xhtml+xml
application/xml
font/eot
font/opentype
image/bmp
image/svg+xml
image/vnd.microsoft.icon
image/x-icon
text/cache-manifest
text/css
text/javascript
text/plain
text/vcard
text/vnd.rim.location.xloc
text/vtt
text/x-component
text/x-cross-domain-policy
text/xml
;
Nun könnt ihr die Konfiguration für verschiedenen allgemeine Einstellungen anlegen.
nano /etc/nginx/conf.d/general.conf
Von mir empfohlener Inhalt:
sendfile on;
tcp_nopush on;
tcp_nodelay on;
keepalive_timeout 65;
types_hash_max_size 2048;
server_tokens off;
index index.php index.html index.htm;
client_max_body_size 0;
include /etc/nginx/mime.types;
default_type application/octet-stream;
access_log /var/log/nginx/access.log;
error_log /var/log/nginx/error.log;
Zum Abschluss könnnt ihr die Hauptkonfiguration von Nginx löschen und neu erstellen.
rm /etc/nginx/nginx.conf && nano /etc/nginx/nginx.conf
Von mir empfohlener Inhalt:
user www-data;
worker_processes auto;
pid /run/nginx.pid;
include /etc/nginx/modules/*.conf;
events {
worker_connections 1024;
multi_accept off;
}
http {
include /etc/nginx/conf.d/*.conf;
include /etc/nginx/sites/*;
}
Die Pfade beim jeweiligen include von modules (modules-enabled) und sites (sites-enabled) müsst ihr natürlich ändern, wenn ihr die Ordner nicht wie oben bei "Optional" angegeben umbenannt habt!
Die Konfiguration von Nginx ist damit fast abgeschlossen, es fehlt nur noch eine Seitenkonfiguration. Diese könnt ihr nun erstellen, domain.tld solltet ihr als Dateinamen und in der nachfolgenden Beispielkonfiguration natürlich zu eurer URL ändern.
nano /etc/nginx/sites/domain.tld
Von mir empfohlener Inhalt:
server {
listen 80;
server_name www.domain.tld domain.tld;
return 301 https://domain.tld$request_uri;
}
server {
listen 443 ssl;
server_name www.domain.tld;
ssl_certificate /etc/nginx/sslcerts/domain.tld/fullchain.pem;
ssl_certificate_key /etc/nginx/sslcerts/domain.tld/privkey.pem;
return 301 https://domain.tld$request_uri;
}
server {
listen 443 ssl http2;
server_name domain.tld;
ssl_certificate /etc/nginx/sslcerts/domain.tld/fullchain.pem;
ssl_certificate_key /etc/nginx/sslcerts/domain.tld/privkey.pem;
root /cloud/websites/domain.tld;
access_log /var/log/nginx/domain.tld_access.log;
error_log /var/log/nginx/domain.tld_error.log error;
include /etc/nginx/snippets/php_7-3.conf;
include /etc/nginx/snippets/cache.conf;
}
Wichtig: Den nach "root" angegeben Pfad müsst ihr natürlich anpassen, je nachdem wo auf dem Server sich eure Webseite befindet. Allgemein gilt /var/www/ als Standardordner für Webseiten, ihr könnt euch das aber frei aussuchen. Wichtig ist nur, dass ihr das in der entsprechenden Seitenkonfiguration richtig angebt.
Subdomain: Wenn ihr eine Subdomain (sub.domain.tld) für eure Seite nutzen möchtet, müsst ihr den 2. server{} Block entfernen. Dieser ist lediglich dafür gedacht, bei Aufruf von www.domain.tld auf domain.tld umzuleiten. Bei einer Subdomain führt das allerdings zu einer Endlosschleife.
Das war es auch schon zu Nginx, ihr habt jetzt einen fertig eingerichtet Webserver mit PHP und HTTPS Verschlüsselung. Ich habe bewusst darauf verzichtet, die diversen Konfigurationen einzeln aufzuschlüsseln. Erfahrungsgemäß möchten die meisten sowieso nur fertige Konfigurationen zum kopieren haben. Ihr könnt aber ganz einfach die jeweiligen Einträge (z.B. "client_max_body_size") bei Google eingeben und bekommt jede Menge Infos dazu. Zum Abschluss müsst ihr Nginx natürlich wieder starten.
service nginx start
MariaDB (MySQL)
Nun könnt ihr MariaDB installieren und anschließend direkt das mitgelieferte Script zum Einrichten ausführen.
apt install -y mariadb-server
mysql_secure_installation
Ihr werdet nun ein paar Sachen abgefragt
- Enter current password; mit Enter bestätigen
- Set root password?; mit Enter bestätigen
- New password; ein sicheres Passwort eingeben
- Re-enter new password; euer Passwort erneut eingeben
- Remove anonymous users?; mit Enter bestätigen
- Disallow root login remotely?; mit Enter bestätigen
- Remove test database and access to it?; mit Enter bestätigen
- Reload privilege tables now?; mit Enter bestätigen
Das war auch schon alles, MariaDB ist damit fertig eingerichtet.
phpMyAdmin
Wenn ihr möchtet, könnt ihr noch phpMyAdmin einrichten, um eure MariaDB Datenbanken im Browser verwalten zu können. Die Webanwendung ist kostenlos und kann direkt auf phpmyadmin.net heruntergeladen werden. Theoretisch kann man es sogar aus den Paketquellen mit apt installieren, würde ich in dem Fall aber wegen der Aktualität von abraten.
Nachdem ihr euch das Archiv von der Webseite heruntergeladen habt, könnt ihr es irgendwo entpacken und mit dem FTP Programm eurer Wahl auf euren Server laden. Ich empfehle aus Sicherheitsgründen keinen Unterordner einer bestehenden Webseite zu nutzen, sondern ein neues Verzeichnis zu erstellen und eine Subdomain mit Verzeichnisschutz dafür einzurichten. Erstellt dazu einen Ordner an einer Stelle eurer Wahl.
mkdir /cloud/websites/phpmyadmin.domain.tld
Anschließend ladet ihr mit eurem FTP Programm die Dateien aus dem entpackten Ordner ("phpMyAdmin-5.0.0-all-languages" oder ähnlich) in das gerade erstellte Verzeichnis hoch. Dann erstellt ihr eine Seitenkonfiguration in Nginx für die Subdomain. Die entsprechende Subdomain solltet ihr natürlich bei eurem Hoster bzw. Registrar vorher eingerichtet haben.
nano /etc/nginx/sites/phpmyadmin.domain.tld
Von mir empfohlener Inhalt:
server {
listen 80;
server_name phpmyadmin.domain.tld;
return 301 https://phpmyadmin.domain.tld$request_uri;
}
server {
listen 443 ssl http2;
server_name phpmyadmin.domain.tld;
ssl_certificate /etc/nginx/sslcerts/phpmyadmin.domain.tld/fullchain.pem;
ssl_certificate_key /etc/nginx/sslcerts/phpmyadmin.domain.tld/privkey.pem;
root /cloud/websites/phpmyadmin.domain.tld;
access_log /var/log/nginx/phpmyadmin.domain.tld_access.log;
error_log /var/log/nginx/phpmyadmin.domain.tld_error.log error;
include /etc/nginx/snippets/php_7-3.conf;
include /etc/nginx/snippets/cache.conf;
auth_basic "Restricted";
auth_basic_user_file /cloud/websites/phpmyadmin.domain.tld/.htpasswd;
}
Ihr benötigt nun noch eine ".htpasswd" Datei im phpMyAdmin Verzeichnis. Diese beinhaltet User und Passwort für den Verzeichnisschutz. Bitte nehmt da nicht das selbe Passwort wie für den MySQL root!
nano /cloud/websites/phpmyadmin.domain.tld/.htpasswd
Den Inhalt könnt ihr euch generieren, es gibt diverse Generatoren über Google zu entdecken. Ihr könnt euch auch selbst einen Generator in php erstellen, dafür reicht der folgende Code:
$user = 'DEIN_USER';
$pw = 'DEIN_PASSWORT';
$password = crypt($pw, base64_encode($pw));
echo $user . ':' . $password;
Die Ausgabe dieser PHP Datei könnt ihr dann in eurer .htpasswd eintragen. Für "Bob" mit Passwort "hallowelt123" sieht das beispielsweise so aus:
bob:aGtMptpFqcGHw
Anschließend besorgt ihr euch noch ein TLS Zertifikat für die Subdomain.
certbot certonly --rsa-key-size 4096 -d phpmyadmin.domain.tld --nginx
Nun müsst ihr nur noch Nginx neustarten und könnt anschließend das Webinterface von phpMyAdmin über https://phpmyadmin.domain.tld/ aufrufen.
service nginx restart
Ihr werdet allerdings feststellen, dass ihr euch nicht mit dem root Account einloggen könnt. Das liegt an den Sicherheitseinstellungen von MariaDB. Da ihr wahrscheinlich keine Lust habt, immer über die Shell neue MySQL Accounts anzulegen und diese dann für den Zugriff auf verschiedene Datenbanken in phpMyAdmin zu nutzen, zeige ich euch, wie ihr diese Sicherheitseinstellung abschalten könnt. Man könnte natürlich, wie es manche Guides zeigen, einen Admin Account anlegen und diesem alle Rechte geben. Das kommt aus sicherheitstechnischer Sicht aber meiner Ansicht nach auf das selbe raus, wie den Login mit dem root Account zu aktivieren. Den Login als root Account könnt ihr wie folgt über die Shell aktivieren (Befehle nacheinander eingeben).
mysql -u root
use mysql;
update user set plugin='' where User='root';
flush privileges;
exit;
Anschließend einfach die Seite mit phpMyAdmin neu laden und schon könnt ihr euch mit dem root Account und dem im MariaDB Abschnitt vergebenen Passwort einloggen.
Zur Begrüßung werden euch wahrscheinlich gleich 3 rote Meldungen entgegen winken. Aber keine Sorge, die sind schnell zu beheben. Zuerst werdet ihr auf die fehlende PHP Erweiterung mbstring hingewiesen, die ihr also kurz installiert und anschließend nginx neustartet.
apt install -y php7.3-mbstring && service nginx restart
Anschließend könnt ihr die phpMyAdmin Seite neuladen, die Meldung sollte verschwunden sein. Als nächstes kümmert ihr euch um die fehlende "secret passphrase".
cp /cloud/websites/phpmyadmin.domain.tld/config.sample.inc.php /cloud/websites/phpmyadmin.domain.tld/config.inc.php
nano /cloud/websites/phpmyadmin.domain.tld/config.inc.php
Gebt nun bei "$cfg['blowfish_secret']" eine 32 Zeichen lange Passphrase ein. Die müsst ihr euch nicht merken, also nehmt einfach irgendwelche Buchstaben, Zahlen und Sonderzeichen. Speichert die Datei ab und ladet die Seite neu. Ihr müsstet euch nun neu einloggen müssen. Anschließend ist die Meldung aber verschwunden. Für die letzte Meldung, reicht es das angegebene Verzeichnis zu erstellen und www-data als Besitzer des Verzeichnisses einzutragen. Letzteres machen wir direkt für das komplette Verzeichnis.
mkdir /cloud/websites/phpmyadmin.domain.tld/tmp
chown -R www-data:www-data /cloud/websites/phpmyadmin.domain.tld/
Nach einem letzten Neuladen der phpMyAdmin Seite sollten nun alle roten Meldungen verschwunden sein und ihr seid fertig mit der Einrichtung.
Zuletzt bearbeitet: 29.05.2020