Episode 68/2017: Durcheinander scp, ssh und uwsgi

Wieder was gelernt. Genauer gesagt, drei Dinge. Fangen wir an:

  1. Caching mit nginx ist eine tolle Sache. Auf einem Server wollten wir die Auswirkung von „Microcaching“, bei dem die Ressourcen beispielsweise nur 1 Sekunde lang vorgehalten werden, prüfen. Caching-Parameter gibt es z.B. als proxy_cache_*, scgi_cache_* oder fastcgi_cache_* Direktiven. Wir brauchten die uwsgi_cache-Direktiven für eine Django-App.
    Alles da, wunderbar.
    Aber: Ausgerechnet das tolle uwsgi-Modul hat keinen Defaultwert beim uwsgi_cache_key. Der Key setzt sich normalerweise aus verschiedenen Parametern wie dem Schema, dem Host und dem Request-URI zusammen, darüber wird ein MD5-Hash gebildet und die Dateien darüber identifiziert.
    Bei leerem Cache-Key wird genau eine Datei zwischengespeichert (die erste, die angefragt wurde) und jeder weitere Request führt zur gleichen Datei. Nicht gut.
  2. Kopieren mit scp. Du sitzt auf Rechner A, willst etwas von Rechner B auf Rechner C kopieren? Von A aus hast Du Zugriff auf B, aber wenn dann von B nach C kopiert wird, fehlen C die entsprechenden Credentials – was tun?
    „scp -3“ kopiert die Datei von B nach A und dann von A nach B. Schön unauffällig, aber sehr praktisch.
  3. Du hast eine ~/.ssh/config Datei mit verschiedenen nützlichen und spezifischen Host-Angaben, insbesondere gibst Du via IdentityFile Deinen Key an? Wenn Du sicherstellen willst, dass wirklich genau nur dieser Key benutzt wird und keine anderen beim Verbindungsaufbau probiert werden, setze „IdentitiesOnly yes“ mit dazu.
    Sagt die Doku: „Specifies that ssh(1) should only use the authentication identity and certificate files explicitly configured in the ssh_config files or passed on the ssh(1) command-line […]“.

Das wars.

Tag 281/2016: Lua

Lua kommt dieses Wochenende auf die Todo-Liste. Es wird Zeit, ein paar Sachen direkt in vorgelagerte Proxies auszulagern, statt die (langsamen) Anwendungen dahinter mit Anfragen zu belästigen.

Weblinks von Wikipedia:

Tag 279/2016: Reguläre Ausdrücke, PCRE

Reguläre Ausdrücke sind Quell eleganter Lösungen und zerraufter Haare. Manche lösen gerne Puzzles, andere entziffern gerne in Gruppen angeordnete negative Lookaheads. Ein paar schnelle Links mit knappem und präzisem Das-wichtigste-was-man-wissen-sollte-Gehalt sowie Dokumentationen für Python, PHP & Javascript.

The absolute bare minimum every programmer should know about regular expressions

5 Regular Expressions Every Web Programmer Should Know

Extreme regex foo: what you need to know to become a regular expression pro

Python-Documentation: Regular expression operations und ein Online-Testtool

PHP-Documentation: Regular expressions (Perl-compatible)

Javascript-Documentation: RegExp

nginx benutzt PCRE in location-Blöcken, maps und beim ngx_http_rewrite_module (einfaches Beispiel).

RegExpBuddy, eine von vielen gelobte kostenpflichtige Software zum Testen von regulären Ausdrücken, leider nur unter Windows.

Tag 270/2016: Links für 12 Wochen Urlaub

http://riemann.io/
Aggregation von Events

http://socket.io/
Bidirektionale ereignisbasierte Echtzeitkommunikation

http://speed.pypy.org/
Eine Implementation von CPython

https://falconframework.org/
Schnelles, minimalistisches Python-Framework

http://openresty.org/download/agentzh-nginx-tutorials-en.html

 

Tag 195/2016: nginx response filter

Wer nginx als Proxy verwendet, konfiguriert im Regelfall die Header, die an den Upstream weitergegeben werden, z.B. den Host-Header oder die IP-Adresse des eigentlichen Clients (und nicht von nginx selbst) als X-Real-IP oder X-Forwarded-For. Darüber hinaus ist es oft notwendig, Redirects des Upstream zu erkennen und auf einen anderen Host oder Port umzuschreiben, gleiches gilt für Cookies.

In seltenen Fällen muss man aber noch weiter gehen und nicht nur die Header, sondern den Response umschreiben, z.B. bestimmte im HTML enthaltene Strings (Formular-Ziele, Script- oder CSS-Links).

Dafür gibt es das ngx_http_sub_module:

location / {
    sub_filter '<a href="http://127.0.0.1:8080/'  '<a href="https://$host/';
    sub_filter '<img src="http://127.0.0.1:8080/' '<img src="https://$host/';
    sub_filter_once on;
}

Tag 181/2016: Projekt stackshare.io

Wenn die halbe Welt eine Information auf deiner Website will, dann reicht unter Umständen der kleine Shared-Hosting-Webserver oder der über DSL via externem DNS-Dienst angebundene Raspberry-Pie nicht mehr aus. Wenn zur Weihnachtszeit Millionen Menschen Fußwärmersocken beim großen Shop ordern, werden virtuelle Maschinen im Dutzend hochgefahren. Wie skaliert man sein Projekt? Wie macht man es hochverfügbar? Seiten wie z.B. highscalability.com geben einen guten Einblick über Konzepte und Lessons learned.

Doch es geht noch „granularer“ – ein interessantes Projekt hab ich jetzt in irgendeinem Newsletter erwähnt gefunden: stackshare.io. Es informiert darüber, welche Projekte welchen Software-Stack, also die Kombination aus Anwendungen, Tools, Utilities aber auch Strategien, einsetzen. Sehr interessant! Über alle Elemente kann abgestimmt und kurz begründet werden, was man daran besonders schätzt. Bei  „Slack“ z.B. die einfache Integration, bei „Sentry“ die Konsolidierung ähnlicher Fehler, bei „nginx“ dessen Performance usw.

Aus den Daten und Angaben, die stackshare von Entwicklern und dem Feedback gewinnt, lassen sich interessante Einblicke gewinnen, siehe den Blog-Post „The Next Generation of Software Stacks“ (Slack, GitHub und Amazon EC2 als Hauptbestandteil des Software-Ökosystems). Zukünftige Software muss in hohem Maße Integrationsfähigkeiten zu anderer Software und Diensten aufweisen.

Ich glaube, die Seite werde ich noch öfter besuchen, dort gibt es noch viel zu entdecken.

Good night and good luck.

Tag 172/2016: Indianerspiele und der Mittelsmann

Viele Blogs und Content-Management-Systeme sind ziemlich mit dem Apache-Webserver verheiratet, insbesondere machen sie reichlich Gebrauch von den verfügbaren Apache-Modulen (rewrite, setenvif, expires, auth_basic, deflate, unique_id uvm).

Eingebürgert hat sich, dass die Einstellungen in dezentrale Konfigurationsdateien geschrieben werden, bei Apache in der Voreinstellung als .htaccess definiert (veränderbar mit der AccessFileName-Direktive). Manche Plugins passen die .htaccess-Dateien sogar sehr häufig an, beispielsweise um IP-Adressen zu blockieren oder durchzulassen.

Der Aufbau der .htaccess-Datei ist dabei leicht verständlich, da von oben nach unten zu lesen. Eine kurze if-Abfrage ob das entsprechende Modul vorhanden ist, danach die spezifischen Anweisungen. Hin und wieder gibt es vielleicht Konfigurationsfehler mit unschönen HTTP-Statuscode-500 „Internal Server Error“ Meldungen, weil die AllowOverride-Direktive in der Hauptkonfigurationsdatei eine spezifische Einstellung nicht erlaubt – aber im großen und ganzen hat sich das Schema bewährt (wenn auch nicht unbedingt unter dem Gesichtspunkt der Performance).

Seit einiger Zeit wird nun der Webserver nginx immer beliebter und dieser kennt keine dezentralen zur Laufzeit gelesenen Konfigurationsdateien. Vor allem die CMS‘, die stark auf mod_rewrite setzen und eine Menge Umleitungsregeln definiert haben, können oft nicht so schnell migriert werden.

Für PHP-Anwendungen mit großer mod_rewrite-etc.-Abhängigkeit, die aber trotzdem gut performen sollen, habe ich ein Setup mit nginx + Microcaching + Request-Limits, Apache mit mod_event (statt prefork) + mod_proxy/fcgi + PHP-FPM ausprobiert. Da gibt es zahlreiche Stellschrauben für die Performance; Hauptvorteil ist, dass die Ressourcen explizit definiert sind und eigentlich kaum der Fall eintritt, dass die Maschine 100% Last erreicht. Allerdings bin ich zu Beginn gleich in eine Situation geraten, in der ein CMS nicht mit PHP 7 lauffähig war, die ältere (distributionseigene) PHP-Version aber noch nicht den fastcgi-Patch hatte, der die besondere Art der sprechenden Pfade des CMS erlaubt hätte. So ist das Leben.

Trotzdem: Der Mittelsmann, hier Apache mit mod_event, soll auch noch weg. Eher früher als später. Glücklicherweise beginnen mehr und mehr Projekte, Profile für nginx zu entwickeln. Manche Anweisungen in liebgewonnenen oder unbedingt notwendigen Plugins lassen sich mit geübtem Auge auch selbst umschreiben. Dass nicht mehr die Reihenfolge, sondern die Spezifität der Anweisung entscheidend für die Ausführung ist, kann durchaus in unüberschaubare Situationen führen. Gute Kommentare oder auch Tests können da Abhilfe schaffen.

Ich baue gerade ein kleines Ansible-Playbook, in dem Apache nicht mehr vorkommt und nginx via fastcgi direkt mit PHP-FPM kommuniziert. Neben der Performance auch ein Gewinn an Übersichtlichkeit und einem Prozess weniger, dessen Ressourcen man messen, schätzen und anpassen muss.

Tag 84/2016: How to deny requests by filename, extension and patterns with nginx in a comfortably bureaucratic manner

In a current setup where nginx acts as a reverse proxy to some Apaches I want to deny access to some useless Flotsam & Jetsam files.

What I not want is to craft wonderful regular expressions that suffice type 3 of a Chomsky-Hierarchy while learning about Pumping-Lemmata, albeit that sounds very alluring for an annoyingly hot summerday later this year (Todo).

So in order to keep my various location directives specific as they are I create a map like this (example):

map $uri $reqhide {
 default 0;
 "~*robots.txt$" 0;
 "~*\.(md|txt)$" 1;
 "~*liesmich\.html$" 1;
}

This map has to be created in the http context of a config file and can then be used in if-conditions within location blocks. It uses the special parameter default to set the variable $reqhide in case of any non-matching pattern. If I want to hide files later on like all .txt files I set $reqhide to 1. A request for „robots.txt“ is caught by the first matching regular expression, so a request for „foo.txt“ is caught by the second that goes for all .txt files. The complete order of priority is explained in the map-module-docs.

As this wonderfully unknown (to many) article on nginx.com notes, the only 100% safe things in if conditions are return and rewrite statements.

So I just do something like

location / {
  [...]
  if ($reqhide) {
    return 404;
  }
  [...]
}

to make the response a 404-File-not-found lie.

Tag 40/2016: Faschingsdienstag-Erkenntnisse

Dies und das.

  • Auf einem der Mailserver habe ich eine fail2ban-Regel, die jeden via DNSBL abgelehnten Einlieferungsversuch findet und die IP für ein paar Stunden sperrt. Das via Munin geplottete Resultat über die letzten Wochen zeigt das Ansteigen der IP-Sperren immer über die Mittagszeit.
  • HTTP/2-Experimente sind notwendig, um mit dem Protokoll der Zukunft frühzeitig Erfahrungen zu sammeln. Dieser Blog-Post hat mich auf diese Implementierung Nghttp2 gebracht. Als weitere Alternative zum ngx_http_v2-Modul von nginx.
  • Gluster und Ceph kenne ich und ich bin in dem Zusammenhang heute über Sheepdog gestolpert. Bookmark gesetzt. Notiz: Demnächst mal das gluster_volume Modul von Ansible laufen lassen, auf das mich die Readme vom geerlingguy-Repository zur GlusterFS-Rolle gebracht hat.
  • WordPress at Scale hat Potential, ist im Moment aber noch ein bisschen zu Highlevel. Am Besten ergänzen mit highscalability.com.