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:
Code: Alles auswählen
# apt install -y apache2
Code: Alles auswählen
$ systemctl is-active apache2.service
active
Code: Alles auswählen
# mkdir /var/www/dampf
Code: Alles auswählen
<h1>Hallo DAMPF!</h1>
Code: Alles auswählen
<VirtualHost *:80>
DocumentRoot /var/www/dampf
ServerName localhost
</VirtualHost>
Code: Alles auswählen
# a2ensite dampf.conf
Code: Alles auswählen
# a2dissite 000-default.conf
Code: Alles auswählen
# systemctl reload apache2.service
M wie MariaDB
Weiter geht es mit der Installation von MariaDB, welches ein (für unsere Zwecke vollständig kompatibler) Fork von MySQL ist:
Code: Alles auswählen
# apt install -y mariadb-server
Code: Alles auswählen
# mariadb-secure-installation
Code: Alles auswählen
# 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
- Es wird ein neuer Benutzer namens dampf mit dem Passwort topsecret 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 Datenbank dampf.
- Die alten Berechtigunge werden “gespült” (und anschliessend neu geladen).
- Die MariaDB-Konsole wird verlassen.
Code: Alles auswählen
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);
Code: Alles auswählen
$ mariadb --database=dampf --user=dampfer --password <dampf.sql
Enter password: *********
Code: Alles auswählen
$ 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 |
+----+---------------------------+------------------+----------+---------+
Um die Dampfwaren aus der Datenbank auf eine Webseite zu bringen wird PHP benötigt, welches in Version 8.2 installiert werden soll:
Code: Alles auswählen
# apt install -y php8.2
Code: Alles auswählen
$ php -r 'echo("PHP Version " . phpversion() . " läuft.\n");'
PHP Version 8.2.7 läuft
Code: Alles auswählen
<?php
echo("<h1>Hallo DAMPF!</h1>");
echo("<p>" . "PHP Version " . phpversion() . " läuft.</p>");
?>
Code: Alles auswählen
# rm /var/www/dampf/index.html
Um mehr über die Umgebung zu erfahren, soll zusätzlich die Datei /var/www/dampf/phpinfo.php mit folgendem Inhalt angelegt werden:
Code: Alles auswählen
<?php
phpinfo();
?>
Code: Alles auswählen
Server API: Apache 2.0 Handler
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.
Code: Alles auswählen
# apt install -y php8.2-fpm libapache2-mod-fcgid
Das Apache-Modul mod_php muss deaktiviert; das Proxy-Modul für FastCGI muss aktiviert werden:
Code: Alles auswählen
# a2dismod php8.2
# a2enmod proxy_fcgi
Code: Alles auswählen
# a2enconf php8.2-fpm
Damit die Änderungen wirksam werden, muss die Konfiguration von Apache neu geladen werden:
Code: Alles auswählen
# systemctl reload apache2
Code: Alles auswählen
Server API: FPM/FastCGI
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):
Code: Alles auswählen
<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>
Code: Alles auswählen
# apt install php-mysql
Code: Alles auswählen
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)
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 Direktiven env (Array) und clear_env (yes/no).
- Das assoziative Array $_SERVER von PHP.
- 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.