{"id":1647,"date":"2016-04-17T21:46:26","date_gmt":"2016-04-17T19:46:26","guid":{"rendered":"http:\/\/blog.benny-baumann.de\/?p=1647"},"modified":"2016-04-17T21:46:26","modified_gmt":"2016-04-17T19:46:26","slug":"verteilte-nutzung-von-php-fpm","status":"publish","type":"post","link":"https:\/\/blog.benny-baumann.de\/?p=1647","title":{"rendered":"Verteilte Nutzung von PHP-FPM"},"content":{"rendered":"<p>PHP mit einem Apache oder einem nginx zu nutzen ist inzwischen kein Hexenwerk mehr. \u00dcberall im Netz findet man haufenweise Konfigurationsbeispiele, die mehr oder minder formal beschreiben, warum man diesen oder jenen Voodoo treiben muss. Was aber scheinbar niemand wirklich erkl\u00e4rt, ist ein kleines, aber essentielles Detail, was einem einiges an Resourcen spart, wenn man \u00fcber mehrere Container hinweg seine Services isolieren m\u00f6chte.<!--more--><\/p>\n<p>Das \u00fcbliche Setup sieht in dieser Umgebung so aus, dass man einen zentralen Server &#8211; aus Performance-Gr\u00fcnden meist etwas Performantes wie nginx &#8211; auf einem Container installiert, und von diesem via Reverse Proxy die Anfragen zu seinem eigentlichen Service weiterleitet. Der Webservice hat in diesem Setup wiederum einen Webserver laufen, der die Anfragen verarbeitet und an PHP durchreicht.<\/p>\n<p>Einfach. Langweilig. Und Bloated!<\/p>\n<p>Denn warum eigentlich den zweiten Webserver? nginx kann doch schon direkt FastCGI sprechen; da brauch man doch keinen eigenen Server, dessen einzige Aufgabe es ist &#8211; neben Taktzyklen verbrennen -, die Anfragen von A nach B durchzureichen.<\/p>\n<p>Gesagt, getan und auf einer meiner Service-Maschinen lediglich den PHP-FPM f\u00fcr die Verarbeitung der Anfragen aufgesetzt. Diesen im Pool auf&#8217;s LAN-Interface der Bridge geklemmt (mit Firewalling gegen das b\u00f6se Internet gesch\u00fctzt) und als erlaubten Client den Proxy eingetragen. Einmal Service neustarten und der PHP-FPM l\u00e4uft.<\/p>\n<p>Was jetzt noch fehlt, ist der grandios undokumentierte Teil der Aufgabe: Wie bekommt der PHP-FPM seine Requests vom nginx? Und vor allem: Woher wei\u00df er, welches Skript auszuf\u00fchren ist?<\/p>\n<p>Nunja, anhand der Konfiguration des nginx nat\u00fcrlich! In dieser gibt es \u00fcblicherweise eine Reihe Konfigurationszeilen mit fastcgi_param zum verdrehen diverse Einstellungen und zur \u00dcbergabe so manch sinnvoller Information wie der verwendeten Server-Software \ud83d\ude09 Unter anderem bietet der nginx hierbei auch einen Wert mit dem unscheinbaren Namen &#8222;SCRIPT_FILENAME&#8220; (nicht verwechseln mit dem &#8222;SCRIPT_NAME&#8220;!!!), welcher 1:1 vom PHP-FPM hinter dem konfigurierten TCP-Socket ausgef\u00fchrt wird. Der hier angegebene Dateiname bezieht sich auf das von PHP-FPM gesehene Dateisystem; inkluse ggf. vorhandener chroot-Umgebungen.<\/p>\n<p>Soweit so einfach, ABER: Da der nginx in diesem Setup keine Dateien der Webanwendung kennt, m\u00fcssen ALLE Anfragen \u00fcber den PHP-FPM laufen (ja, selbst das Ausliefern von Bildern muss via PHP gemacht werden). Da in diesem Setup auch die G\u00fcltigkeitspr\u00fcfung der Dateinamen erst vom angeh\u00e4ngten Webservice erfolgen kann, ist dieser f\u00fcr die korrekte Beantwortung verantwortlich.<\/p>\n<p>Im besten Falle hat man also eine Anwendung, die sowieso Single Entry Point l\u00e4uft und daher alles direkt erledigen kann. Dann vereinfacht sich die Server-Konfiguration auf folgende wenige Zeilen:<\/p>\n<pre lang=\"nginx\">\r\nlocation \/ {\r\n    # regex to split $uri to $fastcgi_script_name and $fastcgi_path\r\n    fastcgi_split_path_info ^(.+\\.php)(\/.+)$;\r\n\r\n    fastcgi_index       index.php;\r\n    fastcgi_pass        12.34.56.78:9000;\r\n    include             fastcgi_params;\r\n    fastcgi_param       SCRIPT_FILENAME         \/srv\/webapp\/index.php;\r\n    fastcgi_param       SCRIPT_NAME             $fastcgi_script_name;\r\n}\r\n<\/pre>\n<p>Danach auch dem nginx einen kurzen Tritt geben, damit er die Konfig neu liest und der schlank aufgesetzte Webservice ist verf\u00fcgbar. Die \u00fcblichen Ma\u00dfnahmen zur Absicherung von PHP-Installationen gelten nat\u00fcrlich uneingeschr\u00e4nkt.<\/p>\n<p class=\"wp-flattr-button\"><a href=\"https:\/\/blog.benny-baumann.de\/?flattrss_redirect&amp;id=1647&amp;md5=36c2708892bcd30318f838b5f694ce60\" title=\"Flattr\" target=\"_blank\"><img src=\"http:\/\/blog.benny-baumann.de\/wp-content\/plugins\/flattr\/img\/flattr-badge-large.png\" srcset=\"http:\/\/blog.benny-baumann.de\/wp-content\/plugins\/flattr\/img\/flattr-badge-large.png\" alt=\"Flattr this!\"\/><\/a><\/p>","protected":false},"excerpt":{"rendered":"<p>PHP mit einem Apache oder einem nginx zu nutzen ist inzwischen kein Hexenwerk mehr. \u00dcberall im Netz findet man haufenweise Konfigurationsbeispiele, die mehr oder minder formal beschreiben, warum man diesen oder jenen Voodoo treiben muss. Was aber scheinbar niemand wirklich erkl\u00e4rt, ist ein kleines, aber essentielles Detail, was einem einiges an Resourcen spart, wenn man [&hellip;]<\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"ngg_post_thumbnail":0,"footnotes":""},"categories":[4],"tags":[156,344,21,346],"class_list":["post-1647","post","type-post","status-publish","format-standard","hentry","category-server","tag-apache","tag-nginx","tag-php","tag-server"],"_links":{"self":[{"href":"https:\/\/blog.benny-baumann.de\/index.php?rest_route=\/wp\/v2\/posts\/1647","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/blog.benny-baumann.de\/index.php?rest_route=\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/blog.benny-baumann.de\/index.php?rest_route=\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/blog.benny-baumann.de\/index.php?rest_route=\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/blog.benny-baumann.de\/index.php?rest_route=%2Fwp%2Fv2%2Fcomments&post=1647"}],"version-history":[{"count":1,"href":"https:\/\/blog.benny-baumann.de\/index.php?rest_route=\/wp\/v2\/posts\/1647\/revisions"}],"predecessor-version":[{"id":1648,"href":"https:\/\/blog.benny-baumann.de\/index.php?rest_route=\/wp\/v2\/posts\/1647\/revisions\/1648"}],"wp:attachment":[{"href":"https:\/\/blog.benny-baumann.de\/index.php?rest_route=%2Fwp%2Fv2%2Fmedia&parent=1647"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/blog.benny-baumann.de\/index.php?rest_route=%2Fwp%2Fv2%2Fcategories&post=1647"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/blog.benny-baumann.de\/index.php?rest_route=%2Fwp%2Fv2%2Ftags&post=1647"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}