Der Apache-Webserver ist das Non Plus Ultra in Sachen Webserver-Software. Seit mehr als 15 Jahren führt der Platzhirsch die Liste der meist genutzen Webserver an. Aktuell, im Februar 2011, werden bei Netcraft 171,195,554 Hostnamen mit Installationen des Apachen gemessen. Das sind 60.10% aller Webserver-Installationen weltweit.
Marktanteile Top-Server über alle Domains Aug. 1995 – Feb. 2011. Quelle: netcraft.com
Seine weite Verbreitung, immerhin ist der Apache fast bei jedem Betriebssystem außer Windows dabei, die Anzahl der erhältlichen Erweiterungen und Module und die relativ leichte Konfiguration, auch in Massenhosting-Umgebungen, machen den Apache auch für Einsteiger zu einem Webserver der ersten Wahl. Wer jedoch mit viel Traffic zu tun hat und dabei eine serverseitige Skriptsprache wie PHP, Perl, Ruby oder ähnliches einsetzt, wird mit dem Apachen früher oder später an seine Grenzen stossen. Es ist mit Hilfe von Reduzierung auf wesentliche Module, Performance-Tuning und Tuning des Linux Systems natürlich sehr viel raus zu holen, doch irgendwann steht die Frage nach einer Alternative im Raum.
Hier war bis vor wenigen Jahren gerade im Linux-Bereich der Webserver lighttpd auf dem Weg eine echte Alternative zu werden, wurde jedoch im Jahr 2008 sehr schnell von einem Webserver Namens nginx überholt. nginx hat aktuell eine Verbreitung von 7.57% auf 21,570,463 Hosts. Tendenz stark steigend.
Der von Igor Sysoev ursprünglich für die russische Suchmaschine Rambler entwickelte nginx-Webserver, der auch als Reverse Proxy und E-Mail-Proxy verwendet werden kann, zeichnet sich durch seine hohe Performance und leichte Konfiguration aus. Gerade in Sachen Performance hat er den Apache schon einige Male in die Ecke verwiesen. nginx wird auch bereits von vielen High-Traffic-Seiten wie beispielsweise Golem.de, WordPress.com, t3n.de, GitHub und vielen weiteren mehr eingesetzt. Auch als zusätzliche Software zum Beispiel als Load-Balancer, Proxy, SSL-Proxy oder für das Ausliefern von reinen statischen Inhalten wie Grafiken, Stylesheets oder Videos eignet sich nginx durch seine kurzen Responce-Zeiten sehr gut.
Die Software zu installieren ist im Prinzip nicht weiter schwierig, sofern man Linux-Grundkenntnisse mitbringt. Download, Configure, Make, Install, Konfigurationsfiles anpassen und fertig ist die nginx-Installation. Doch eins nach dem anderen und auch für Einsteiger etwas langsamer erklärt. Ich möchte hier an einem Beispiel aufzeigen, wie man den nginx-Webserver installiert, konfiguriert und für das Ausliefern von statischen Webseiten vorbereitet.
Die aktuelle stabile Version erhalten wir auf der Webseite des nginx. Aktuell ist die Version 0.8.54 vom 14.12.2010, die man unter folgenden URL downloaden kann:
http://nginx.org/download/nginx-0.8.54.tar.gz
Mit Linux macht man das am besten mit wget:
# wget http://nginx.org/download/nginx-0.8.54.tar.gz
Jetzt muß man den Tarball nur noch entpacken und es kann zur Installation übergehen.
# tar -xvzf nginx-0.8.54.tar.gz
Jetzt wechseln wir in das entpackte Verzeichnis. Um den nginx mit Standard-Modulen zu installieren reicht ein einfaches configure aus.
# cd nginx-0.8.54
# ./configure
Dies bereitet die Kompilierung des nginx in das Verzeichnis /usr/local/nginx mit Standard-Modulen wie dem HTTP-Kernmodul, HTTP-Upstreammodul, HTTP-Zugriffsmodul, HTTP-Authentifizierungsmodul und Fastcgi-Modul vor. Die Ausgabe der Zusammenfassung sollte so oder so ähnlich aussehen:
Configuration summary
+ using system PCRE library
+ OpenSSL library is not used
+ md5: using system crypto library
+ sha1 library is not used
+ using system zlib library
nginx path prefix: "/usr/local/nginx"
nginx binary file: "/usr/local/nginx/sbin/nginx"
nginx configuration prefix: "/usr/local/nginx/conf"
nginx configuration file: "/usr/local/nginx/conf/nginx.conf"
nginx pid file: "/usr/local/nginx/logs/nginx.pid"
nginx error log file: "/usr/local/nginx/logs/error.log"
nginx http access log file: "/usr/local/nginx/logs/access.log"
nginx http client request body temporary files: "client_body_temp"
nginx http proxy temporary files: "proxy_temp"
nginx http fastcgi temporary files: "fastcgi_temp"
nginx http uwsgi temporary files: "uwsgi_temp"
nginx http scgi temporary files: "scgi_temp"
Im nächsten Schritt heisst es kompilieren und installieren:
# make
# make install
Sollten diese beiden Make-Befehle ohne Fehler ausgeführt werden ist nginx nun unter dem Verzeichnis /usr/local/nginx installiert.
Beginnen wir nun mit der Konfiguration. Im Prinzip können die Standard-Einstellungen übernommen werden, da sie für das Ausliefern von statischen Webseiten völlig ausreichend sind. Dennoch möchten wir hier einige Einstellungen variieren und jeweils noch die gewünschten Server bzw. Domains anlegen. Die Konfiguration befindet sich in der Datei /usr/local/nginx/conf/nginx.conf, die wir mit dem Editor unserer Wahl, in meine Fall der vi-Editor, öffnen:
# vi /usr/local/nginx/conf/nginx.conf
An erster Stelle finden wir die globalen Einstellungen. Hier können Werte definiert werden, die für den gesamten Server gelten. Dazu gehören der User und die Gruppe unter der die Server-Prozesse laufen, Logfiles, Pidfile und Angaben zu Prozessen und MaxClients.
# User und Gruppe unter der der nginx läuft
user www www;
# Anzahl der Worker-Prozesse
worker_processes 2;
# Anzahl der maximalen Worker-Connections
events {
worker_connections 512;
}
# Ort und LogLevel der ErrorLog-Datei
error_log logs/error.log notice;
# Ort des Pidfiles
pid logs/nginx.pid;
Standardmässig läuft der nginx unter dem User nobody, was wir je nach Belieben anpassen können. Allerdings sollte man einen Werbserver niemals unter dem Benutzer root laufen lassen, um eventuellen Sicherheitslücken vorzubeugen.
Die Anzahl der Worker-Prozesse gibt an, wieviele Prozesse gestartet werden sollen. Der nginx startet einen Master-Prozess, der die Verwaltung übernimmt und die in der Konfiguration angegebene Anzahl von Worker-Prozessen. Diese Worker-Prozesse sind für die Verbindungen zum Benutzer und das Ausliefern der Webseite zuständig. 2 Worker-Prozesse sollten für den Anfang ausreichend sein.
Die Anzahl der Worker-Connections bestimmt die maximale Anzahl von gleichzeitigen Verbindungen, die ein Worker-Prozess verarbeiten kann. Aus beiden Werten von worker_processes und worker_connections ergibt sich hier also die maximale Anzahl von gleichzeitigen Verbindungen für den gesamten Webserver, der so genannten auch aus der Apache-Konfiguration bekannten Variable MaxClients. Die Formel hierfür ist
max_clients = worker_processes * worker_connections
In unserem Fall 2 * 512 = 1024. 1024 Verbindungen sollten für den Anfang mehr als ausreichend sein und können bei Ressourcenmangel ruhig auch bis 250 minimiert werden.
Den Ort und LogLevel der ErrorLog-Datei, sowie den Ort des Pidfiles können wir getrost so übernehmen.
Jetzt kommen wir zur Konfiguration des HTTP-Services und der einzelnen Server. Die Standard-Einstellungen sollten angepasst werden und wurden von mir für optimale und performante Auslieferung mit Hilfe von Gzip, Cache-Einstellungen usw. optimiert. Nehmen wir als Beispiel die IP 1.2.3.4 und eine Domain Namens www.meinedomain.de mit statischen HTML-Seiten, Bildern, Stylesheets und einigen Download-Dateien im Verzeichnis /var/www/meinedomain.de/htdocs, welches natürlich vorhanden sein sollte. Auch an SEO sollten wir gleich denken, die Domain wirklich nur unter einer Domain erreichbar machen und alles andere auf diese per 301-Weiterleitung weiterleiten.
http {
# die Konfiguration der Content-Typen aus conf/mime.types inkludieren
include mime.types;
# Der Standard-Content-Typ
default_type application/octet-stream;
# Support für größere Dateien
sendfile on;
# HTTP Response-Header in einem Paket senden
tcp_nopush on;
# Sekunden, in denen auf eine erneute Verbindung vom
# gleichen Client gewartet wird
keepalive_timeout 65;
# Disable Nagle's buffer algorithm
tcp_nodelay on;
# Gzip aktivieren, sendet komprimierte Daten zum Client
gzip on;
gzip_comp_level 2;
gzip_proxied any;
gzip_types text/plain text/css application/x-javascript text/xml application/xml application/xml+rss text/javascript;
# Definition des Logfile-Formats
log_format vhosts '$http_host $remote_addr - $remote_user [$time_local] '
'"$request" $status $body_bytes_sent '
'"$http_referer" "$http_user_agent"';
# VHost-Konfiguration
server {
# IP-Adresse und Port, an denen für Web-Zugriffe gelauscht wird
listen 1.2.3.4:80;
# Domains, auf die dieser Server hören soll
server_name www.meinedomain.de meinedomain.de;
# Hauptverzeichnis für Dokumente
root /var/www/meinedomain.de/htdocs;
# Ort des Access-Logfiles
access_log /var/www/meinedomain.de/logs/access_log vhosts;
# Definition des Index-Files (Startseite, für Anfragen ohne Dateiname)
index index.html;
# Wenn Zugriff auf andere als Standarddomain,
# auf diese per 301 permanent weiterleiten
if ($host != 'www.meinedomain.de' ) {
rewrite ^/(.*)$ http://www.meinedomain.de/$1 permanent;
}
# Für Bilder und einige andere Dateitypen Access-Log ausschalten und
# Expire-Zeit auf 7 Tage erhöhen (sendet den entspr. Expire-Header)
location ~* ^.+\.(js|css|jpg|jpeg|gif|png|pdf|zip|rar)$ {
access_log off;
expires 7d;
}
location / {
# Nützlich für SSL und evtl. später hinzukommende Scriptsprachen
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header Host $http_host;
proxy_redirect off;
# Wenn die angeforderete statische Datei existiert, diese ausliefern
# ohne die anderen Regeln weiter unten zu beachten
if (-f $request_filename) {
break;
}
# index.html für Unterverzeichnisse
if (-f $request_filename/index.html) {
rewrite (.*) $1/index.html break;
}
}
}
}
Die Konfiguration besteht aus dem Part http mit Definitionen für diesen Service. Hier wird zuerst die Mime-Konfiuration geladen, Einstellungen zum Connection-Verhalten gesetzt, das Gzip-Modul zum komprimieren der Daten aktiviert und die Definition des Logfile-Formates vorgenommen. Weiter finden wir innerhalb des http-Parts den server-Part, die Konfiguration der einzelnen Websites, auch genannt VHosts. Ich habe auch hier die einzelnen Direktiven oben kommentiert, weshalb ich auf weitere detailiertere Beschreibung verzichte. Im Prinzip ist alles selbsterklärend. Will man weitere Domains bzw. Server hinzufügen muß man lediglich den Part server {} kopieren. Dabei ist darauf zu achten, daß jede Konfiguration nacheinander innerhalb von http {} steht. Ab zwei Servern lohnt es sich schon, für jeden Server ein eigenes Konfigurationsfile anzulegen. Hierfür erstellt man innerhalb des conf-Verzeichnisses ein Unterverzeichnis, zum Beispiel „sites“ und inkludiert die darin enthaltenen Files einfach innerhalb des http-Parts:
include /usr/local/nginx/conf/sites/*;
Jetzt kann man sich für jede Domain ein eigenes Konfigurationsfile anlegen, was wesentlich übersichtlicher ist.
Was uns jetzt noch fehlt ist, den nginx das erste Mal zu starten. Hierfür benötigen wir ein sogenanntes Startskript, welches wir z.B. hier für Ubuntu bekommen und unter /etc/init.d/nginx ablegen. Alternativ kann es hier kopiert und für evtl. andere Distributionen angepasst werden:
#!/bin/sh
#This is a start script for nginx. Tested on Unbuntu Edge.
#Should work on Ubuntu, Debian and probably a few other Linux distros.
#Change DAEMON and CONFIG_FILE if neccessary
PATH=/sbin:/bin:/usr/sbin:/usr/bin
#Location of nginx binary. Change path as neccessary
DAEMON=/usr/local/nginx/sbin/nginx
#Location of configuration file. Change path as neccessary
CONFIG_FILE=/usr/local/nginx/conf/nginx.conf
DAEMON_OPTS="-c $CONFIG_FILE"
NAME=nginx
DESC="web server"
PIDFILE=/var/run/$NAME.pid
SCRIPTNAME=/etc/init.d/$NAME
#only run if binary can be found
test -x $DAEMON || exit 0
set -e
#import init-functions
. /lib/lsb/init-functions
case "$1" in
start)
log_daemon_msg "Starting $DESC" $NAME
if ! start-stop-daemon --start --quiet\
--pidfile $PIDFILE --exec $DAEMON -- $DAEMON_OPTS ; then
log_end_msg 1
else
log_end_msg 0
fi
;;
stop)
log_daemon_msg "Stopping $DESC" $NAME
if start-stop-daemon --quiet --stop --oknodo --retry 30\
--pidfile $PIDFILE --exec $DAEMON; then
rm -f $PIDFILE
log_end_msg 0
else
log_end_msg 1
fi
;;
reload)
log_daemon_msg "Reloading $DESC configuration" $NAME
if start-stop-daemon --stop --signal 2 --oknodo --retry 30\
--quiet --pidfile $PIDFILE --exec $DAEMON; then
if start-stop-daemon --start --quiet \
--pidfile $PIDFILE --exec $DAEMON -- $DAEMON_OPTS ; then
log_end_msg 0
else
log_end_msg 1
fi
else
log_end_msg 1
fi
;;
restart|force-reload)
$0 stop
sleep 1
$0 start
;;
*)
echo "Usage: $SCRIPTNAME {start|stop|restart|reload|force-reload}" >&2
exit 1
;;
esac
exit 0
Jetzt noch mit chmod das Ausführen der Datei erlauben:
# chmod 700 /etc/init.d/nginx
Nun können wir uns freuen und den nginx das erste Mal starten:
# /etc/init.d/nginx start
Ist alles korrekt und das Konfigurationsfile ohne Fehler, sollte der nginx starten und die Webseite unter der konfigurierten Domain erreichbar sein.
Damit der nginx auch beim nächsten Server-Neustart automatisch startet, benötigen wir einen Eintrag bzw. einen symbolischen Link im Runlevel-Startverzeichnis, hier als Beispiel für Ubuntu:
ln -s /etc/init.d/nginx /etc/rc2.d/S99nginx
Somit startet nginx beim nächsten Neustart des Servers im Runlevel 2 automatisch. Falls ein anderes Runlevel läuft (ersichtlich mit dem Befehl „runlevel“), einfach den Link im jeweiligen Verzeichnis erstellen.
Das wars! Ich hoffe ich konnte Dir hier einen kleinen Einstieg in nginx vermitteln. Ein Artikel zur Verwendung von PHP und Installation von WordPress folgt demnächst. Bei Fragen, Verbesserungen oder Angregungen freue ich mich über Kommentare.
– nginx-Webseite
– nginx-Wiki
– nginx bei Wikipedia
– nginx bei Ubuntu
pdo
performt richtig geil im vergleich zu Apache :-)
New Media – Performance, Performance, Performance!
Aziz Ghannami
bastey
Servus,
ich bin eben auf der Suche nach einer Problemlösung hier gelandet (www.domain.tld != domain.tld) und wollte nur sagen: schicker Artikel.
Noch eine Anmerkung: Um dem nginx-Server PHP nachzubringen, gibt es nichts einfacheres als den FastCGI Process Manager (PHP-FPM). Und wenn man dann noch APC dabei hat, gibt es keine schnellere Webserverlösung.
Matthias
Nico
danke Dir! Ja, die Auslieferung der statischen Seiten erfolgt aus Performancegründen, um den MySQL-Server nicht unnötig oft zu malträtieren und um den Vorteil der wesentlich besseren Responsezeiten bei statischen Dateien zu nutzen. Es ist eine Arbeitsentlastung für den Server, denn was einmal aus der Datenbank gelesen und per PHP erstellt wurde, also das fertige HTML-Dokument, muß so nicht bei jedem Aufruf aufs Neue passieren.
Der nächste Artikel ist schon fast fertig, inkl. Rewrite-Rules ;-)
LG,
Nico
Was denkst du?