lighttpd

Aus wiki.archlinux.de
Die druckbare Version wird nicht mehr unterstützt und kann Darstellungsfehler aufweisen. Bitte aktualisiere deine Browser-Lesezeichen und verwende stattdessen die Standard-Druckfunktion des Browsers.

lighttpd ist ein sehr leichtgewichtiger, einfach zu administrierender, performanter HTTP-Server, der vor allem überall da eingesetzt wird, wo die Geschwindigkeit entscheidend ist und wo hohe Zugriffszahlen zu erwarten sind. So geben unter anderem YouTube, Wikipedia und SourceForge lighttpd den Vorzug gegenüber Apache und ähnlich umfangreichen HTTP-Servern.

Auch einfach nur als schlanke Alternative zu Apache ist lighttpd geeignet. Dieser Artikel beschreibt, wie man eine vollwertige Serverumgebung bestehend aus lighttpd, PHP, MySQL (bzw. MariaDB) und Python aufsetzt.

Installation

lighttpd ist als lighttpd in extra verfügbar, und kann von dort mittels Pacman installiert werden.

# lighttpd an sich
pacman -S lighttpd

# Sinnvoll für Webserver
pacman -S php php-cgi mariadb mariadb-clients

PHP und das CGI-Modul für PHP, sowie MariaDB nebst Clients sind ebenfalls in extra vorhanden und sollten gleich mitinstalliert werden.

Konfiguration

Bevor lighttpd gestartet werden kann, muss er noch konfiguriert werden. Die Konfiguration wird in der Datei /etc/lighttpd/lighttpd.conf vorgenommen. Die meisten Optionen in der Standard-Konfiguration sind bereits mit sinnvollen Werten belegt.

Module

Der Abschnitt „server.modules“ definiert, welche zusätzlichen Module von lighttpd geladen werden sollen. Für einen sinnvollen Betrieb sind die Module „fastcgi“ und „cgi“ zusätzlich zu den bereits aktivierten Modulen nötig. Somit ergibt sich folgende Konfiguration der Module:

server.modules = (
  "mod_access",
  "mod_fastcgi",
  "mod_cgi",
  "mod_accesslog" )

Auskommentierte Module sind in der Ansicht weggelassen worden. Interessant kann noch „userdir“ sein, was /home/user/public_html ermöglicht (Aufrufbar sind diese Verzeichnisse mittels http://host/~user).

Verzeichnis- und Dateinamen

Standardmäßig verwendet lighttpd das Verzeichnis /srv/http als Wurzelverzeichnis der HTML-Dateien. Wenn man dies so belassen möchte, kann man das natürlich, muss dann aber darauf achten, dass dieses Verzeichnis entweder eine eigene Partition hat, oder die Partition auf der sich dieses Verzeichnis befindet, groß genug ist.

Besser ist es, das Wurzelverzeichnis des Servers auf eine eigene Partition zu legen. Hier kann man auch die Rechte entsprechend restriktiv setzen (noexec als Mountoption zum Beispiel), um den Server etwas sicherer zu machen.

server.document-root = "/media/webserver"

Index-Dateien werden immer dann angezeigt, wenn man ein Verzeichnis über HTTP aufruft. Sofern keine Index-Datei vorhanden ist, wird entweder der Verzeichnis-Inhalt angezeigt, oder es wird eine Fehlermeldung ausgegeben, dass der Verzeichnisinhalt nicht angezeigt werden kann.

Will man zum Beispiel, dass start.htm als Indexdatei verwendet wird, trägt man dies in die Indexdateiliste ein. Beim Aufruf von http://host/blubb/ wird die Indexdateiliste durchgegangen, und sobald eine Datei mit einem Dateinamen aus der Liste vorhanden ist, wird sie Angezeigt, ohne, dass man den Dateinamen angeben muss. Im Beispiel wird durch den Aufruf von http://host/blubb/ die Datei http://host/blub/start.htm angezeigt.

index-file.names = ( "index.php", "index.html", "start.htm" )

Der Abschnitt „mimetype.assign“ ordnet bestimmten Dateiendungen definierte Dateiinhalts-Typen zu. Wenn man eigene Dateiendungen benutzt, die einen bestimmten Inhalt haben, kann man diese hier hinzufügen. Es sind allerdings schon alle gängigen Typen definiert, so dass man hier im Normalfall nichts mehr ändern muss.

Serveroptionen

Will man nicht, dass jemand, der die Seite aufruft, als Information bekommt, dass es sich beim HTTP-Server um lighttpd handelt, kann man dies mittels der Option „server.tag“ ändern.

server.tag = "blubb"

Hiermit wird per HTTP-Header der Servername „blubb“ an den aufrufenden Client übermittelt. Es gibt allerdings außer dem Servertag noch weitere Möglichkeiten, mittels derer auf den tatsächlichen Server geschlossen werden kann.

Will man bestimmte Dateitypen nicht per HTTP ausliefern, kann man dies mittels der Liste „url.access-deny“ bewerkstelligen. So werden standardmäßig Backup-Dateien (dateiname~) und Include-Dateien (dateiname.inc) ausgeschlossen. Will man weitere Dateitypen von der Auslieferung ausschließen, fügt man die Endungen dieser einfach der Liste hinzu.

Standardmäßig lauscht lighttpd wie jeder andere HTTP-Server auf Port 80. Dies kann man über „server.port“ ändern, und lighttpd zum Beispiel auf Port 5678 lauschen lassen.

server.port = 5678

Ein Client, der auf den Server zugreift, kann aber dennoch durch einfaches Portscanning, z.B. mittels nmap herausfinden, auf welchem Port was lauscht, und somit natürlich auch, dass auf Port 5678 ein HTTP-Server lauscht.

Will man lighttpd nur als lokales Testsystem betreiben, und will nicht, dass beliebige Clients auf den Server zugreifen können, kann man lighttpd an eine bestimmte IP binden. Im Falle des lokalen Testsystems ist dies zum Beispiel 127.0.0.1.

server.bind = "127.0.0.1"

Will man virtuelle Hosts verwenden, so muss man das Server-Modul „mod_simple_vhost“ aktivieren und die Optionen gemäß der Kommentare in der Konfigurationsdatei setzen.

simple-vhost.server-root   = "/media/webserver/vhosts/"
simple-vhost.default-host  = "myhost.invalid"
simple-vhost.document-root = "/htdocs/"

Das Wurzelverzeichnis setzt sich dann standardmäßig aus den drei Angaben in dieser Reihenfolge zusammen.

Ansonsten wird der Mittelteil (im Beispiel „myhost.invalid“) automatisch durch den Hostnamen ersetzt, über den der Server aufgerufen wird. Wenn man zum Beispiel mittels „server.lan“ auf den Server zugreift, ist das HTML-Wurzelverzeichnis

/media/webserver/vhosts/server.lan/htdocs/

Die weiter oben angesprochenen Verzeichnis-Listen bei fehlender Indexdatei kann man mittels der Option „dir-listing.activate“ beeinflussen. „enable“ aktiviert die Verzeichnisauflistung, „disable“ deaktiviert sie.

dir-listing.activate = "enable"
dir-listing.encoding = "utf-8"

Bei deaktivierter Verzeichnisauflistung und fehlender Indexdatei wird ein Hinweis an den Client übermittelt, dass die Datei nicht gefunden werden konnte (404 NOT FOUND). Standardmäßig ist das Listing deaktiviert.

Betrieb

Der Server läuft standardmäßig nicht mit root-Rechten, sondern mit den Rechten des Users und der Gruppe „http“. Dieser User darf sich nicht einloggen (er hat statt einer Shell /bin/false, das bei jedem Einlogversuch eine Fehlermeldung zurückgibt), was einen gewissen Grad an Sicherheit mit sich bringt.

Wenn man den Server als Produktivsystem betreiben will, sollte man dies auch so lassen, und das Dokumenten-Wurzelverzeichnis des Servers dem entsprechenden User und der entsprechenden Gruppe zuordnen. Wenn man andere User nun ebenfalls dieser Gruppe zuordnet können diese User auch in diesem Wurzelverzeichnis (und darunter) arbeiten.

Will man lighttpd als lokales Testsystem verwenden, kann man ihn auch mit den Rechten eines anderen Benutzers (z.B. sich selbst) laufen lassen. Vorteil ist, dass es weniger Rechteprobleme gibt, da alle Dateien dem User gehören, unter dem auch der Webserver läuft.

server.username = "username"
server.group = "users"

Nachteil ist hier, dass der HTTP-Server mit den selben Rechten läuft, die auch der entsprechende User innehat. Ein erfolgreicher Angreifer oder ein fehlerhaftes Script können somit auf alle Daten zugreifen, auf die auch der entsprechende User Zugriff hat. Dieses Setup sollte ausschließlich in von Außen nicht erreichbaren Umgebungen umgesetzt werden.

  • Es ist ratsam einen so konfigurierten Webserver nicht permanent laufen zu lassen, sondern ihn nur dann zu starten, wenn er auch tatsächlich zum Entwickeln/Testen verwendet werden soll.

MariaDB und PHP

Durch die Verwendung von MariaDB und PHP erreicht man ein vollwertiges Serversystem, das mit allen gängigen Webanwendungen kompatibel ist. Apache-Spezifische Funktionen in den Webanwendungen werden für gewöhnlich allerdings nicht direkt unterstützt, diese sind – abgesehen von htaccess (siehe dort) – allerdings auch relativ selten.

PHP

Um PHP verwenden zu können, muss der fastcgi-Server noch konfiguriert werden, hierzu befindet sich in der Konfigurationsdatei von lighttpd auch schon ein auskommentierter Eintrag, der verwendet werden kann. Es müssen der Binärpfad zu PHP und die socket-Datei von PHP angegeben werden. Zudem muss definiert werden, von welcher Endung PHP-Dateien sind.

fastcgi.server =( ".php" => ((
  "bin-path" => "/usr/bin/php-cgi",
  "socket" => "/tmp/php.socket"
)))

Zusätzlich muss in der Konfigurationsdatei von PHP die Option „cgi.fix_pathinfo“ auf 1 gesetzt (Einkommentiert) werden. Um MariaDB verwenden zu können muss zudem die PHP-Erweiterung mysql aktiviert werden, dies geschieht in der selben Datei durch das Einkommentieren der entsprechenden Option.

; …
; …
extension=mysql.so
; …
; …

Den häufig als Sicherheitsfunktion erwähnten Save-Mode von PHP kann man ebenfalls aktivieren (save_mode = On), allerdings ist er seit PHP-Version 5.3.0 als deprecated markiert und wird in PHP 6 entfernt werden.

MariaDB

Zu allererst sollte ein root-Passwort für MariaDB vergeben werden. Dies hat mit dem System-root-Account nichts zu tun, sondern bezieht sich nur auf den MariaDB-Server. Das Passwort wird mittels des MariaDB-Administrationstools gesetzt.

mysqladmin -uroot password 'daswunschpasswort'

Somit kann man nur noch mittels Passwort als root auf die Datenbank zugreifen. Weitere MariaDB-User können ebenfalls eingerichtet werden: Hierzu muss man sich als root auf dem MariaDB-Server anmelden, und einen bestimmten SQL-String übergeben.

mysql -uroot -p
[…]
> USE mysql;
> INSERT INTO user (host, user, password)
  VALUES('localhost','username',password('daswunschpasswort'));

Danach muss der MariaDB-Server mittels systemctl restart mariadb neu gestartet werden. Bezüglich der weitergehenden Berechtigungsstruktur innerhalb des MariaDB-Servers bitte die in den Weblinks verknüpfte Setup-Anleitung konsultieren. Alternativ bietet sich das GRANT-System an.

mysql -uroot -p
[…]
> CREATE DATABASE testdb;
> GRANT USAGE
  ON *.*
  TO 'testuser'@'localhost'
  IDENTIFIED BY 'daspasswort';

Hiermit wird der MariaDB-User testuser angelegt. Zuvor wird noch die Datenbank testdb angelegt. Beim Anlegen des Users werden diesem jegliche Privilegien für alle Datenbanken entzogen (USAGE ist in der SQL-Syntax ein Synonym für „keine Privilegien“). Nun kann man diesem User Berechtigungen für eine spezifische Datenbank erteilen

> GRANT select,insert,update,delete,create,drop
  ON testdb.*
  TO 'testuser'@'localhost'

Hiermit wird dem eben angelegten User für die eben angelegte Datenbank lesender und schreibender Zugriff gewährt. Der User kann Tabellen anlegen und löschen, aber die Datenbank selbst kann er nicht verändern. Der User kann nur vom Server aus auf die Datenbank zugreifen („localhost“) und nicht von anderen Systemen aus.

Python

Damit lighttpd Python-Scripte ausführen kann, muss eine entsprechende Zuweisung in der Konfigurationsdatei vorgenommen werden. Es wird davon ausgegangen, dass Python über /usr/bin/python angesprochen wird.

cgi.assign = ( ".py" => "/usr/bin/python" )

Außerdem muss Python bei den Dateiendungen hinzugefügt werden.

static-file.exclude-extensions = ( .., .., ".py" )

Damit dies funktioniert, muss mod_cgi aktiviert sein.

Starten

lighttpd ist ein Service, das heißt, dass er für den Automatischen Start aktiviert werden sollte.

systemctl enable lighttpd

Manuell gestartet werden kann lighttpd mittels systemctl start lighttpd. Sollte man den User und die Gruppe geändert haben, kann es beim Starten zu einem Berechtigungsfehler bezüglich des Logfiles kommen. Das (eventuell nötige) manuelle Anlegen des Logfile-Verzeichnisses und das zuweisen des Benutzers und der Rechte behebt das Problem.

mkdir /var/log/lighttpd
chown username:log /var/log/lighttpd
chmod 760 /var/log/lighttpd

Alternativ kann man auch in der lighttpd-Konfigurationsdatei über die Option „accesslog.filename“ (und weitere) die Logfile-Dateien an einem Ort erstellen lassen, an dem der entsprechende User Schreibrechte hat.

Testen

Ausgabe von phpinfo(); in Firefox

Testweise kann man nun im Dokumenten-Wurzelverzeichnis eine Datei info.php anlegen, und <?php phpinfo(); ?> hineinschreiben. Dies ist eine PHP-Informations-Funktion. Beim Aufruf der Seite über http://localhost/info.php erscheint eine Übersicht darüber, was der Server kann, und wie er konfiguriert wurde.

In dem Dokument erhält man Informationen über die PHP-Installation, MariaDB, den Webserver, und das System, auf dem der Server läuft.

Diese Datei sollte man auf einem öffentlich erreichbaren Produktivsystem nicht zugänglich lassen, da die verwendete PHP-Funktion einem Angreifer viele Informationen über das System zugänglich macht. Man sollte die Datei also löschen oder aber zumindest nicht unter einem leicht erreichbaren Dateinamen abspeichern.

Besonderheit: htaccess

lighttpd kann nicht mit htaccess-Dateien umgehen. Das heißt, dass alle Webanwendungen, die auf htaccess zurückgreifen, nicht direkt lauffähig sind. Dies betrifft Weiterleitungen sowie als auch Zugangsmechanismen. lighttpd verwaltet derlei Dinge in der vHost-Konfiguration.

Hierzu gibt es in der Datei /etc/lighttpd.conf mehrere Abschnitte $HTTP["host"] =~ "hostname.tld". Innerhalb dieser Abschnitte werden alle diesen Host betreffenden Angaben zu Login-Abfragen, URL-Rewriting, etc. getätigt.

Damit URL-Rewriting und Login-Abfragen funktionieren, müssen im Abschnitt server.modules die Module mod_auth und mod_rewrite aktiviert werden.

URL-Rewriting

Die Konfiguration von URL-Rewrites wird mittels der Funktion url.rewrite-TYP vorgenommen, wobei TYP einer der verschiedenen von lighttpd verwendbaren Typen ist. rewrite-once entspricht dem von htaccess bekannten Verhalten.

url.rewrite-once = (
  "/angegeber_pfad" => "weiterleitung_auf.php"
)

Weitere Typen sind rewrite-repeat (entspricht der Angabe [L] bei htaccess-Weiterleitungen) und url.rewrite-[repeat-]if-not-file (entspricht der htaccess-Angabe !-f).

Beispiel

Wenn man das Blog-System Wordpress einsetzt, will man vermutlich auch dessen Funktion verwenden, URLs „schön“ darzustellen. Wordpress benutzt dafür htaccess, da dies von lighttpd nicht verwendet wird, muss man die Angaben aus der htaccess-Datei von Wordpress auf url.rewrite-once-Angaben umschreiben. Da die regulären Ausdrücke von htaccess und lighttpds Rewriting-System identisch sind, ist dies Relativ einfach möglich.

$HTTP["host"] =~ "example.com" {
  url.rewrite-once = (
    "^/(.*)\.(.+)$" => "$0",
    "^/(wp-.+)$" => "$0",
    "^/xmlrpc.php" => "$0",
    "^/sitemap.xml" => "$0",
    "^/(.+)/?$" => "/index.php/$1"
  )
}

Wenn das Blog auf example.com liegt, kann man nun Wordpress bei aktiviertem URL-Rewriting von Wordpress mittels der bekannten Wordpress-URLs aufrufen. lighttpd schreibt die URLs automatisch passend um, so wie Apache es anhand der htaccess-Datei auch machen würde.

Authentifizierung

Der HTTP-Authentifizierungsdialog, hier angezeigt von Firefox

Das Login-System von lighttpd funktioniert etwas anders als das von apache (htaccess). Und zwar wird erst definiert, was für ein Authentifizierungs-System verwendet werden soll, und welche Datei (im Falle von dateibasierenden Authentifizierungsmethoden) verwendet werden soll. Dann wird die Authentifizierung mittels des Abschnitts auth.require für einzelne Unterverzeichnisse aktiviert.

auth.backend = "SYSTEM"
auth.backend.SYSTEM.userfile = "/var/www/password"

auth.require = (
  "/unterverzeichnis" => (
    "method" => "Athentifizierungsmethode",
    "realm" => "Text, der im Loginfenster angezeigt wird",
    "require" => "Was als gültiger Login anerkannt wird"
  )
)

Für SYSTEM können folgende Werte verwendet werden:

  • plain – Erwartet die Usernamen und Passwörter im Klartext in der angegebenen Datei.
  • htpasswd – Erwartet Usernamen und Passwörter in der von htaccess-Passwortschutz bekannten Form in der angegebenen Datei.
  • htdigest – Erwartet Usernamen, Realm, und das gehashte (MD5) Passwort in der angegebenen Datei, je Zeile in dieser Reihenfolge durch Doppelpunkte getrennt.

Zusätzlich dazu gibt es auch noch die Möglichkeit, die Authentifizierung via LDAP zu realisieren.

Beispiel

Will man zum Beispiel das Unterverzeichnis /secure auf seinem Server example.com mittels basic-auth vor Zugriffen schützen, verwendet man folgendes:

$HTTP["host"] =~ "example.com" {
  auth.backend = "htpasswd"
  auth.backend.htpasswd.userfile = "/var/www/password"
  auth.require = (
    "/secure" => (
      "method" => "basic",
      "realm" => "Login",
      "require" => "valid-user"
    )
  )
}

Die Datei /var/www/password enthält nun zum Beispiel die Zeilen

user1:mjsHyevlsdf4HeAQ
user2:mjdvGdwe3345HIsd

Somit können sich user1 und user2 mit ihren jeweiligen Passwörtern einloggen (die Hashes im Beispiel sind Zufallswerte und entsprechen keinem dem Autor bekannten Passwort). Als Informationstext bekommen alle, die auf example.com/secure zugreifen wollen „Login“ angezeigt.

Diese Konfiguration entspricht dem htaccess-Basierenden Passwortschutz.

Die Angaben über das Authentifizierungssystem sowie die entsprechende Datei können auch global (außerhalb eines $HTTP["host"]-Blocks) definiert werden.

Anmerkungen

Die Funktionsweise der digest-Methode entspricht noch nicht vollständig dem Standard und ist derzeit noch eher als unsicher einzustufen, da sie zum Beispiel dem Replay-Angriff nicht stand hält.

Die LDAP-Authentifizierung unterstützt derzeit nur Usernamen ohne Sonderzeichen. Der Username „ein.user“ wird von lighttpds LDAP-Authentifizierungssystem derzeit noch mit einer Fehlermeldung verworfen.

Fehlerhafte Loginversuche werden derzeit nicht vernünftig mitgeschnitten („There seems to be no reasonable logging of failed login attempts yet“)

Die Gruppenbasierende Authentifizierung funktioniert derzeit noch nicht. auth.backend.plain.groupfile ist dafür vorgesehen, wird derzeit aber einfach ignoriert.

Siehe auch

Weblinks