Der DAMPF-Stack
LAMP auf Debian (mit FastCGI)
Wer mit Linux unterwegs ist und sich schon etwas mit Web-Entwicklung befasst
hat, dem dürfte der LAMP-Stack bestehend aus Linux, Apache,
MySQL und PHP bereits begegnet sein. Wer mit Debian GNU/Linux arbeitet,
kann das L mit einem D konkretisieren. Und wer PHP via FastCGI statt
mit Apaches mod_php
einbindet, dem dürfte PHP-FPM ein Begriff sein, wodurch
das P zu PF ergänzt wird. So soll hier die Rede vom DAMPF-Stack
sein: Debian, Apache, MariaDB (anstelle von MySQL) und
PHP-FPM.
In diesem Beitrag wird erklärt, wie dieser Stack aufgesetzt und anhand einer minimalen Beispielanwendung in Betrieb genommen wird.
D wie Debian
Die Ausgangslage ist eine Grundinstallation von Debian 12 Bookworm. Grundlegende Kenntnisse von systemd, HTML, SQL und PHP sind dem Verständnis dienlich; die einzelnen Schritte sollten aber auch ohne dieses Vorwissen nachvollziehbar sein.
Als Konvention wird Befehlen, welche Superuser-Berechtigungen erfordern, das
Rautezeichen #
vorangestellt. (Diese Befehle lassen sich per sudo
ausführen.) Befehlen, die man auch ohne Superuser-Berechtigungen ausführen
kann, wird das Dollarzeichen $
vorangestellt.
A wie Apache
Zunächst soll der Apache-Webserver installiert werden:
# apt install -y apache2
Dieser sollte nach der Installation bereits gestartet sein:
$ systemctl is-active apache2.service
active
Unsere DAMPF-Webseite soll in einem neuen Verzeichnis zu liegen kommen:
# mkdir /var/www/dampf
Zu Testzwecken soll eine statische HTML-Seite unter /var/www/dampf/index.html
mit folgendem Inhalt angelegt werden:
<h1>Hallo DAMPF!</h1>
Eine minimale Virtualhost-Konfiguration unter
/etc/apache2/sites-available/dampf.conf
mit folgendem Inhalt wird ebenfalls
benötigt:
<VirtualHost *:80>
DocumentRoot /var/www/dampf
ServerName localhost
</VirtualHost>
Die Seite wird aktiviert, indem man einen symbolischen Link innerhalb von
/etc/apache2/sites-available
zur jeweiligen Konfiguration unter
/etc/apache2/sites-enabled
erstellt. Dies lässt sich man manuell oder
komfortabler mit dem Befehl a2ensite
bewerkstelligen:
# a2ensite dampf.conf
Die Standardseite von Debian 000-default.conf
soll hingegen deaktiviert
werden:
# a2dissite 000-default.conf
Via systemd soll der Apache-Service zum Neuladen der Konfiguration veranlasst werden:
# systemctl reload apache2.service
Anschliessend sollte die Seite unter localhost verfügbar sein.
M wie MariaDB
Weiter geht es mit der Installation von MariaDB, welches ein (für unsere Zwecke vollständig kompatibler) Fork von MySQL ist:
# apt install -y mariadb-server
Für ein produktives Setup lohnt sich das Härten der Datenbankinstallation:
# mariadb-secure-installation
Da je nach Umgebung und Bedürfnissen andere Optionen sinnvoll sind, soll hier
nicht weiter auf diese eingegangen werden. Stattdessen sollen ein neuer
Benutzer namens dampfer
und eine neue Datenbank namens dampf
angelegt
werden:
# mariadb
> CREATE USER dampfer@localhost IDENTIFIED BY 'topsecret';
> CREATE DATABASE dampf CHARACTER SET 'utf8' COLLATE 'utf8_general_ci';
> GRANT ALL PRIVILEGES ON dampf.* TO dampfer@localhost;
> FLUSH PRIVILEGES;
> EXIT
Die Befehle machen folgendes:
- Es wird ein neuer Benutzer namens
dampf
mit dem Passworttopsecret
erstellt. (Mit@localhost
wird angegeben, dass der Benutzer nicht von einem anderen System aus auf die Datenbank zugreifen kann.) - Eine neue Datenbank namens
dampf
mit UTF-8-Kodierung ‒ nein: UTF-8 ist kein character set sondern ein encoding; Unicode wäre ein character set ‒ und entsprechender Collation (zwecks Sortierung) wird erstellt. - Der Benutzer
dampfer
erhält sämtliche Rechte für die Datenbankdampf
. - Die alten Berechtigunge werden “gespült” (und anschliessend neu geladen).
- Die MariaDB-Konsole wird verlassen.
Damit es etwas zum DAMPFen gibt, soll eine entsprechende Datenbank angelegt
werden. Das Skript hierzu wird in der Datei dampf.sql
angelegt:
CREATE TABLE dampfware (
id INTEGER AUTO_INCREMENT PRIMARY KEY,
substanz VARCHAR(255) UNIQUE NOT NULL,
geruch VARCHAR(255) NULL,
stinkend TINYINT(1) NOT NULL DEFAULT 0,
toxisch TINYINT(1) NOT NULL DEFAULT 0
);
INSERT INTO dampfware (substanz, geruch, stinkend, toxisch)
VALUES ("faule Eier", "Schwefel", 1, 0);
INSERT INTO dampfware (substanz, geruch, stinkend, toxisch)
VALUES ("Surströmming", "Verwesung", 1, 0);
INSERT INTO dampfware (substanz, geruch, stinkend, toxisch)
VALUES ("Trifluormethylhypofluorit", NULL, 0, 1);
INSERT INTO dampfware (substanz, geruch, stinkend, toxisch)
VALUES ("Limburger", "faules Gemüse", 1, 0);
INSERT INTO dampfware (substanz, geruch, stinkend, toxisch)
VALUES ("Weihrauch", "Messdienergewand", 0, 0);
INSERT INTO dampfware (substanz, geruch, stinkend, toxisch)
VALUES ("Buttersäure", "Mundgeruch", 1, 1);
Das Skript dampf.sql
soll nun ausgeführt werden, wozu Datenbank, Benutzername
und Passwort (letzteres interaktiv) eingegeben werden müssen. Das Skript wird
via Standard Input eingelesen:
$ mariadb --database=dampf --user=dampfer --password <dampf.sql
Enter password: *********
Zur Kontrolle sollen die Daten noch (tabellarisch: -t
) ausgegeben werden;
zwecks Platzwersparnis mit den kurzen Varianten der Flags:
$ echo 'SELECT * FROM dampfware;' | mariadb -D dampf -u dampfer -p -t
Enter password: *********
+----+---------------------------+------------------+----------+---------+
| id | substanz | geruch | stinkend | toxisch |
+----+---------------------------+------------------+----------+---------+
| 1 | faule Eier | Schwefel | 1 | 0 |
| 2 | Surströmming | Verwesung | 1 | 0 |
| 3 | Trifluormethylhypofluorit | NULL | 0 | 1 |
| 4 | Limburger | faules Gemüse | 1 | 0 |
| 5 | Weihrauch | Messdienergewand | 0 | 0 |
| 6 | Buttersäure | Mundgeruch | 1 | 1 |
+----+---------------------------+------------------+----------+---------+
P wie PHP
Um die Dampfwaren aus der Datenbank auf eine Webseite zu bringen wird PHP benötigt, welches in Version 8.2 installiert werden soll:
# apt install -y php8.2
Der Interpeter soll sogleich mit einem Einzeiler getestet werden:
$ php -r 'echo("PHP Version " . phpversion() . " läuft.\n");'
PHP Version 8.2.7 läuft
Da PHP offenbar funktionstüchtig ist, soll die statische HTML-Seite durch eine
dynamische PHP-Seite mit folgendem Inhalt ersetzt werden
(/var/www/dampf/index.php
):
<?php
echo("<h1>Hallo DAMPF!</h1>");
echo("<p>" . "PHP Version " . phpversion() . " läuft.</p>");
?>
Die alte HTML-Seite kann entfernt werden:
# rm /var/www/dampf/index.html
Unter localhost sollte nun die von PHP dynamisch gerenderte Seite aufgerufen werden.
Um mehr über die Umgebung zu erfahren, soll zusätzlich die Datei
/var/www/dampf/phpinfo.php
mit folgendem Inhalt angelegt werden:
<?php
phpinfo();
?>
Unter localhost/phpinfo.php erfährt man nun u.a. folgendes:
Server API: Apache 2.0 Handler
Das bedeutet, dass PHP von Apache mit mod_php
ausgeführt wird. Ein DAMPF-Stack
ist das noch nicht, es fehlt das F wie FPM.
F wie FPM
FPM steht für FastCGI Process Manager und ist eine Methode um PHP-Code
auszuführen, die gegenüber mod_php
bzw. herkömmlichen CGI einige Vorteile
bietet:
- PHP und Apache müssen nicht mehr mit gleichen Berechtigungen ausgeführt werden.
- Es muss nicht (wie bei CGI) für jede Anfrage ein neuer PHP-Prozess gestartet werden.
- PHP-FPM kann eine Reihe von PHP-Prozessen vorhalten, auf welche die Anfragen dann nebenläufig verteilt werden. Dies führt zu einer höheren Performanz unter starker Last.
Um PHP-FPM verwenden zu können, müssen weitere Pakete installiert werden:
# apt install -y php8.2-fpm libapache2-mod-fcgid
Das Paket php8.2-fpm
ist der Dienst, welcher die PHP-Prozesse verwaltet. Das
Apache-Modul libapache2-mod-fcgid
delegiert die Anfragen, welche die
Ausführung von PHP erfordern, an PHP-FPM weiter.
Das Apache-Modul mod_php
muss deaktiviert; das Proxy-Modul für FastCGI muss
aktiviert werden:
# a2dismod php8.2
# a2enmod proxy_fcgi
Weiter muss die Konfiguration von PHP-FPM aktiviert werden:
# a2enconf php8.2-fpm
Entsprechende symbolische Links werden in /etc/apache2/mods-enabled
und in
/etc/apache2/conf-enabled
erstellt bzw. entfernt.
Damit die Änderungen wirksam werden, muss die Konfiguration von Apache neu geladen werden:
# systemctl reload apache2
Beim nächsten Aufruf von localhost/phpinfo.php sollte nun folgende Angabe erscheinen:
Server API: FPM/FastCGI
Damit wäre der DAMPF-Stack betriebsbereit!
Full Stack DAMPF
Da nun der ganze Stack lauffähig ist, sollen auch alle Komponenten davon eingesetzt werden.
Eine Datenbankverbindung lässt sich mit PHP Data Objects (PDO) erstellen. Die
Verbindung soll dann sogleich verwendet werden um die ganzen DAMPF-Waren als
HTML-Seite auszugeben (/var/www/dampf/dampfwaren.php
):
<ol>
<p>DAMPF-Waren:</p>
<?php
try {
$db = new PDO("mysql:host=localhost;dbname=dampf", "dampfer", "topsecret");
foreach ($db->query("SELECT * FROM dampfware;") as $dw) {
echo("<li value=\"{$dw['id']}\">");
echo("{$dw['substanz']}: {$dw['geruch']}");
echo(" (stinkend: {$dw['stinkend']}, toxisch: {$dw['toxisch']})");
echo("</li>");
}
} catch (PDOException $e) {
die($e);
}
?>
</ol>
Der Datenbanktreiber für MySQL (bzw. für MariaDB) muss noch über das entsprechende Paket installiert werden:
# apt install php-mysql
Anschliessend sollte ein Aufruf von localhost/dampfwaren.php nun folgende Ausgabe erzeugen:
DAMPF-Waren:
1. faule Eier: Schwefel (stinkend: 1, toxisch: 0)
2. Surstömming: Verwesung (stinkend: 1, toxisch: 0)
3. Trifluormethylhypofluorit: (stinkend: 0, toxisch: 1)
4. Limburger: faules Gemüse (stinkend: 1, toxisch: 0)
5. Weihrauch: Messdienergewand (stinkend: 0, toxisch: 0)
6. Buttersäure: Mundgeruch (stinkend: 1, toxisch: 1)
Übungen
Wer den hier beschriebenen DAMPF-Stack mit dieser Anleitung zum Laufen gebracht hat, der hat schon einiges geleistet. Wer noch nicht genug geDAMPFt hat, kann sich an folgenden Übungen versuchen:
- Die Datenbank-Verbindungsdaten sind in
dampfwaren.php
hartkodiert. Dies ist einerseits unflexibel, andererseits sicherheitstechnisch nicht optimal, da Quellcode schnell unwiderruflich in einem Versionierungssystem mit Änderungshistorie landet. Besser wäre es beispielsweise, die Verbindungsdaten in Umgebungsvariablen auszulagern. Hierzu nur einige wenige Stichworte:- Die Datei
/etc/php/8.2/fpm/pool.d/www.conf
mit den Direktivenenv
(Array) undclear_env
(yes
/no
). - Das assoziative Array
$_SERVER
von PHP.
- Die Datei
- Die Ausgabe der DAMPF-Waren als Liste weist noch einige Mängel optischer
Natur auf, die verbessert werden könnten:
- Die Darstellung von geruchlosen Einträgen (Trifluormethylhypofluorit) ist nicht optimal, da auf den Doppelpunkt keine Geruchsbezeichnung folgt, sondern direkt die geklammerten Eigenschaften aufgelistet werden.
- Die
TINYINT(1)
-Felder “stinkend” und “toxisch” könnten besser dargestellt werden. - Eine Tabelle mit Spaltennamen wäre wohl übersichtlicher als eine Aufzählung.