mecker. mecker. mecker.

nginx

07.01.2012, 22:03

Seit heute rennt das Blog unter nginx. Der Grund ist einfach: lighttpd ist behindert zu kon­fi­gu­rie­ren, hat keine aktuellen/coolen Features und ist zudem noch langsamer als nginx. Ich hoffte seit knapp einem Jahr, dass sich in der Ent­wick­lung was tut, aber außer einer Beta-Version mit in­te­grier­tem lua-Support (um überhaupt ein if-else statt if-else-if kon­fi­gu­rie­ren zu können) und zahl­rei­chen Won’t fixes für 1.4.x hat sich leider rein gar nichts getan.

Warum nginx? Ja, das weiß ich auch nicht, aber die Al­ter­na­ti­ven zu non-Apache mit geringem Memory-Footprint, vielen Features und opensource sehen schlecht aus. thttpd hat kein mod_proxy, Cherokee bringt gleich ein Web-GUI zur Ad­mi­nis­tra­ti­on mit und LiteSpeed Web Server ist nicht quell-offen. Also, was sind die Features von nginx?

  • schnell und leicht­ge­wich­tig
  • logische Kon­fi­gu­ra­ti­on (was ich schon für behinderte Logik-Krämpfe mit lighttpd hatte…)
  • mod_proxy, mo­d_­fast­cgi, expires, PCRE

Moving from lighttpd to nginx

Die Umstellung von lighttpd nach nginx ist nicht ganz ohne. Prin­zi­pi­ell ist alles anders und nginx hat keine Un­ter­stüt­zung für CGI und rewrite-Regeln auf Query-Parametern. Außerdem spawnt nginx nicht au­to­ma­tisch einen PHP-Prozess für FastCGI und erlaubt keine POST-Requests auf statische Seiten – aber das lässt sich umgehen.

1. Präambel - /etc/nginx/nginx.conf

user www-data;
worker_processes  2;

error_log  /var/log/nginx/error.log;
pid        /var/run/nginx.pid;

events { worker_connections  2048; }

http {
    include       /etc/nginx/mime.types;

    #access_log /var/log/nginx/access.log;

    # cbc-mode ciphers might be vulnerable (BEAST)
    ssl_ciphers RC4:HIGH:!aNULL:!MD5;
    ssl_prefer_server_ciphers on;

    sendfile        on;
    keepalive_timeout  65;
    tcp_nodelay        on;

    gzip  on;
    gzip_disable "MSIE [1-6]\.(?!.*SV1)";
    index index.php index.htm index.html;

    include /etc/nginx/conf.d/*.conf;

2. vhosts - /etc/nginx/conf.d/posativ.org.conf

server {
    listen       80;
    server_name  posativ.org;
    root         /home/www/posativ.org;

    location ^~ /blog {
        include conf.d/pyblosxom.redirect;
    }

    location ~ ^/(redmine|git)/ {
        rewrite ^/(.*)$ https://posativ.org/$1 redirect;
    }
}

Selbst­er­klä­rend. Nicht mehr und nicht weniger will ich kon­fi­gu­rie­ren. Statt im lighty ir­gend­wel­che obskuren Redirects auf Sockets != 443 zu kreieren, gibt es hier ganz klar das Konzept „ich lausche auf diesen Ports mit folgenden Ein­stel­lun­gen”.

3. SSL

In der Präambel lässt sich zudem noch die verwendete Cipher wählen und so ein Angriff mittels BEAST verhindern.

server {
    listen       443;
    server_name  posativ.org;
    root         /home/www/posativ.org;

    ssl             on;
    ssl_certificate certs/posativ.org.crt;
    ssl_certificate_key certs/posativ.org.key;

    location ^~ /redmine {
        proxy_pass http://127.0.0.1:3001;
    }

    location ^~ /git {
        proxy_pass http://127.0.0.1:7654;
    }

    # ...
}

5. rewrite rules

Das war zunächst das größte Problem. Ich pflege Rück­wärts­kom­pa­ti­bi­li­tät zwischen meinen (inzwischen vier) Blogs mit un­ter­schied­li­cher Software und Permalinks. Einfach sind URI -> URI rewrites-Rules:

    # lighttpd
    url.redirect += ("/blog/?$" => "https://blog.posativ.org/", ...)
 
    # nginx
    rewrite "^/blog/?$" "http://blog.posativ.org/" permanent;
    ...

Mit perl -pe "s/\"(.+)\" => \"(.+)\",/rewrite \"\^\1\" \"\2\" permanent;/g" hatte ich das grob von lighttpd auf nginx übertragen. Problem: nginx kann kein rewrite auf die Request-Parameter (zurecht aber auch). Das sollte nicht nur mich mit meinen an­fäng­li­chen /?p=1dcdd17 stören, auch diverse andere Blogs haben dieses URL-Schema. Warum das nicht direkt von den rewrite-Regeln un­ter­stützt wird, ist klar: die Query-Pa­ra­me­ter­rei­hen­fol­ge ist variabel. Aber es ist nginx und da geht alles (wenn auch mit erhöhtem Re­chen­auf­wand):

location = / {
    # das `?` am Ende leitet die GET-Request Paramter nicht weiter
    if ($arg_p = 1dcdd17) {
        rewrite ^ http://blog.posativ.org/2011/weitere-html-abstraktion-in-python/? permanent;
        # ...
    }
}

6. weitere Ei­gen­hei­ten

  • nginx erlaubt kein POST/PUT auf statisches HTML, denn sonst wäre es ja CGI (was aber auch nicht geht, dazu gleich mehr). Aber auch dafür gibt es die merk­wür­digs­ten Work­a­rounds (POST auf statisches HTML wirft 405):

    error_page 405 = @405;
    location       = @405 {
        root    /home/www/blog.posativ.org;
    }
    
  • CGI wird auch nicht un­ter­stützt, denn es ist langsam und erfordert viel Ver­wal­tungs-Logik. Das macht bsw. lighttpd spei­cher­hung­ri­ger als Apache (!), wenn Google mal ein CGI-hosted Mercurial-Web­in­ter­face crawlt. Statt CGI sollte FastCGI oder Proxy-Magie genutzt werden. Für PHP spawnt nginx keinen Prozess, der muss vorher auch angelegt werden. Für Debian gibt es dafür ein init.d-Skript und nach einem invoke.rc-d start php-fcgi lauscht ein PHP-Prozess auf Port 9000.

Rückblick

lighttpd war zwei Jahre mein treuer Begleiter im Kampf gegen Apaches behinderte XML-like Kon­fi­gu­ra­ti­on mit kleinem Spei­cher­ver­brauch, aber die Kon­fi­gu­ra­ti­on ist inzwischen mehr als will­kür­lich. Schon eine Umordnung von Statements, die logisch gleich­wer­tig sind, kann das Problem lösen oder erst erzeugen.

Die nginx Kon­fi­gu­ra­ti­on ist weitaus intuitiver, besitzt mehr Funk­tio­nia­li­tät und trotzdem ist der Server schlanker, modularer und leis­tungs­fä­hi­ger als lighttpd.

KTHXBYE lighttpd.

blog comments powered by Disqus

written by posativImpressum

by-nc-sa