{"id":11579,"date":"2016-07-23T01:56:11","date_gmt":"2016-07-22T23:56:11","guid":{"rendered":"https:\/\/tuxproject.de\/blog\/?p=11579"},"modified":"2019-05-23T11:30:28","modified_gmt":"2019-05-23T09:30:28","slug":"dynamische-single-serving-sites-mit-openbsd-bordmitteln-erstellen","status":"publish","type":"post","link":"https:\/\/tuxproject.de\/blog\/2016\/07\/dynamische-single-serving-sites-mit-openbsd-bordmitteln-erstellen\/","title":{"rendered":"Dyna\u00admi\u00adsche Sin\u00adgle-Ser\u00adving Sites mit Open\u00adBSD-Bord\u00admit\u00adteln erstel\u00adlen"},"content":{"rendered":"<p>Unter \u201eSin\u00adgle-Ser\u00adving Sites\u201c ver\u00adsteht man gemein\u00adhin Web\u00adsites wie <a href=\"https:\/\/isitchristmas.com\/\">IsItChristmas.com<\/a>, <a href=\"http:\/\/whatismyip.org\/\">WhatIsMyIP.org<\/a> und <a href=\"http:\/\/www.purple.com\">purple.com<\/a>, die als Gegen\u00adent\u00adwurf zu infor\u00adma\u00adti\u00adons\u00ad\u00fcber\u00adla\u00adde\u00adnen Web\u00adpor\u00adta\u00adlen meist genau eine ein\u00adzi\u00adge Fra\u00adge beant\u00adwor\u00adten. Es gibt in der Regel kei\u00adne Unter\u00adsei\u00adten, kei\u00adne <em>ech\u00adte<\/em> Inter\u00adak\u00adti\u00advi\u00adt\u00e4t und auch sonst sind sol\u00adche Web\u00adsites sehr ange\u00adnehm anzu\u00adse\u00adhen.<\/p>\n<p>Meist ist so eine Web\u00adsite schlicht in sta\u00adti\u00adschem HTML geschrie\u00adben wor\u00adden, denn ser\u00adver\u00adsei\u00adti\u00adge Scripts sind eben\u00adso \u00fcber\u00adfl\u00fcs\u00adsig wie jQuery oder ande\u00adre Per\u00adver\u00adsio\u00adnen des Moder\u00adnen. Was aber, wenn man dem Besu\u00adcher etwa abh\u00e4n\u00adgig von sei\u00adner Brow\u00adser\u00adspra\u00adche oder per Zufalls\u00adal\u00adgo\u00adrith\u00admus eine ande\u00adre Ansicht pr\u00e4\u00adsen\u00adtie\u00adren will? Nat\u00fcr\u00adlich k\u00f6nn\u00adte man auf Java\u00adscript zur\u00fcck\u00adgrei\u00adfen; wer das aber nicht m\u00f6ch\u00adte, zum Bei\u00adspiel, weil er sich nicht dar\u00adauf ver\u00adlas\u00adsen m\u00f6ch\u00adte, dass der Besu\u00adcher Java\u00adscript akti\u00adviert hat und einen mit dem geschrie\u00adbe\u00adnen Code kom\u00adpa\u00adti\u00adblen Brow\u00adser benutzt, dem bleibt letzt\u00adlich nur die Nut\u00adzung ser\u00adver\u00adsei\u00adti\u00adgen Codes, etwa Perl oder PHP, \u00fcbrig.<\/p>\n<p>Nun gilt f\u00fcr Ser\u00adver mehr noch als f\u00fcr einen Lap\u00adtop oder PC, dass jede zus\u00e4tz\u00adlich instal\u00adlier\u00adte Soft\u00adware wegen m\u00f6g\u00adli\u00adcher noch unent\u00addeck\u00adter oder unkor\u00adri\u00adgier\u00adter Feh\u00adler ein poten\u00adzi\u00adel\u00adles Sicher\u00adheits\u00adri\u00adsi\u00adko birgt, wozu auch Skript\u00adspra\u00adchen, Web\u00adser\u00adver\u00adsoft\u00adware und sogar Text\u00adedi\u00adto\u00adren z\u00e4h\u00adlen. Dazu kommt der Res\u00adsour\u00adcen\u00adhun\u00adger, den man\u00adcher <em>stack<\/em> mit sich bringt: Benutzt man etwa die belieb\u00adte Kom\u00adbi\u00adna\u00adti\u00adon aus dem Web\u00adser\u00adver <tt>nginx<\/tt> und der Spra\u00adche PHP im Fast\u00adC\u00adGI-Modus (<tt>php-fcgi<\/tt>), ist es kei\u00adne Sel\u00adten\u00adheit, dass auch im <em>Leer\u00adlauf<\/em> diver\u00adse Pro\u00adzes\u00adse an den System\u00adres\u00adsour\u00adcen knab\u00adbern.<\/p>\n<p>L\u00e4sst sich eine sol\u00adche Web\u00adan\u00adwen\u00addung auch pro\u00adgram\u00admie\u00adren, ohne den Ser\u00adver unn\u00f6\u00adti\u00adger Last und Gefah\u00adren aus\u00adzu\u00adset\u00adzen? <!--more-->Nun, je nach Betriebs\u00adsy\u00adstem stellt das tat\u00ads\u00e4ch\u00adlich kein Pro\u00adblem dar, denn zum Bei\u00adspiel Open\u00adBSD ver\u00adf\u00fcgt von Haus aus \u00fcber einen brauch\u00adba\u00adren Text\u00adedi\u00adtor (<tt>vi<\/tt>), einen Fast\u00adC\u00adGI unter\u00adst\u00fct\u00adzen\u00adden Web\u00adser\u00adver (<tt>httpd<\/tt> mit <tt>slow\u00adc\u00adgi<\/tt>) sowie einen C\u2011Compiler (<tt>cc<\/tt>). C mag nicht gera\u00adde eine beson\u00adders ein\u00adsteig\u00ader\u00adfreund\u00adli\u00adche Spra\u00adche sein, aber f\u00fcr ein biss\u00adchen Text\u00adaus\u00adga\u00adbe ist nicht viel Code n\u00f6tig. Ich mach\u2018 mal ein Bei\u00adspiel.<\/p>\n<p>Wir gehen im Fol\u00adgen\u00adden davon aus, dass wir eine bestehen\u00adde Web\u00adsite namens \u201eSind-wir-schon-verloren.net\u201c haben, die bis\u00adher aus einem unter Open\u00adBSD in einem <tt>nginx<\/tt>-Ser\u00adver lau\u00adfen\u00adden PHP-Script besteht, das, wenn ein eng\u00adlisch\u00adspra\u00adchi\u00adger Besu\u00adcher es auf\u00adruft, \u201eYes\u201c, sonst \u201eJa\u201c aus\u00adgibt.<\/p>\n<pre lang=\"html4strict\" escaped=\"true\">&lt;!doctype html&gt;\n&lt;html&gt;\n  &lt;head&gt;\n    &lt;title&gt;Sind wir schon verloren?&lt;\/title&gt;\n  &lt;\/head&gt;\n  &lt;body&gt;\n    &lt;h1&gt;&lt;?php\n      \/* Browsersprache ermitteln: *\/\n      if (substr($_SERVER[\"HTTP_ACCEPT_LANGUAGE\"],0,2) == \"en\") {\n          \/* Aha, ein englischsprachiger Nutzer! *\/\n          echo \"Yes\";\n      }\n      else {\n          \/* Aha, kein englischsprachiger Nutzer! *\/\n          echo \"Ja\";\n      }\n    ?&gt;&lt;\/h1&gt;\n  &lt;\/body&gt;\n&lt;\/html&gt;<\/pre>\n<p>So weit, so ver\u00adst\u00e4nd\u00adlich. PHP hat den <em>Vor\u00adteil<\/em>, dass man es ein\u00adfach in bestehen\u00adde HTML-Sei\u00adten inte\u00adgrie\u00adren kann und der Web\u00adser\u00adver erle\u00addigt den Rest. Aber wir wol\u00adlen ja Res\u00adsour\u00adcen spa\u00adren, also pro\u00adgram\u00admie\u00adren wir das gan\u00adze Ding mal neu.<\/p>\n<p>Wenn ihr Web\u00adser\u00adver wie <tt>nginx<\/tt> oder <tt>lighttpd<\/tt> ein\u00adsetzt, l\u00e4uft PHP bei euch ver\u00admut\u00adlich bereits im Fast\u00adC\u00adGI-Modus. Fast\u00adC\u00adGI bedeu\u00adtet im Wesent\u00adli\u00adchen, dass der Web\u00adser\u00adver lau\u00adfend eini\u00adge Kopien von PHP im Spei\u00adcher h\u00e4lt, die bei einer Anfra\u00adge schnell das <em>gew\u00fcnsch\u00adte Ergeb\u00adnis<\/em> berech\u00adnen, hier also aus der Liste der Auf\u00adruf\u00adva\u00adria\u00adblen die \u00fcber\u00admit\u00adtel\u00adte Liste der unter\u00adst\u00fctz\u00adten Spra\u00adchen her\u00adaus\u00adsu\u00adchen und die ersten zwei Zei\u00adchen die\u00adser Liste, zum Bei\u00adspiel \u201ede\u201c f\u00fcr Deutsch oder \u201een\u201c f\u00fcr Eng\u00adlisch als Haupt\u00adspra\u00adche, mit der Zei\u00adchen\u00adket\u00adte <tt>\u201een\u201c<\/tt> ver\u00adglei\u00adchen. Das klingt nicht nur wie der wohl\u00adbe\u00adkann\u00adte Schuss aus Kano\u00adnen auf Spat\u00adzen, es hat auch \u00e4hn\u00adli\u00adche Kon\u00adse\u00adquen\u00adzen. Dass PHP selbst im Leer\u00adlauf gele\u00adgent\u00adlich CPU-Zeit f\u00fcr sich bean\u00adsprucht, ist nur eine davon.<\/p>\n<p>War\u00adum also bei jedem Auf\u00adruf die gan\u00adze HTML-Sei\u00adte neu kom\u00adpi\u00adlie\u00adren? Viel effi\u00adzi\u00aden\u00adter ist es doch, ein bereits vor\u00adkom\u00adpi\u00adlier\u00adtes Pro\u00adgramm hin\u00adter die\u00adses Fast\u00adC\u00adGI zu h\u00e4n\u00adgen. Damit die\u00adse wie\u00adder\u00adum zus\u00e4tz\u00adli\u00adche Soft\u00adware kei\u00adnen Unsinn anstellt, k\u00f6n\u00adnen wir sie mit dem Open\u00adBSD-Befehl <tt>pledge()<\/tt> <a href=\"http:\/\/www.heise.de\/ix\/meldung\/Eingeschraenkte-Privilegien-Unix-Derivat-OpenBSD-5-9-veroeffentlicht-3157290.html\">unter Kon\u00adtrol\u00adle bekom\u00admen<\/a>. Los geht\u2019s!<\/p>\n<p>Die C\u2011Version unse\u00adrer PHP-Sei\u00adte sieht so aus:<\/p>\n<pre lang=\"c\" escaped=\"true\">\/* Erst mal ein paar Funktionen nachladen: *\/\n#include &lt;stdlib.h&gt;  \/* Standardbibliothek *\/\n#include &lt;stdio.h&gt;   \/* puts() *\/\n#include &lt;string.h&gt;  \/* strncmp() *\/\n#include &lt;stdbool.h&gt; \/* bool *\/\n#ifdef __OpenBSD__\n\/* Unter OpenBSD k\u00f6nnen wir mit pledge() die Sicherheit erh\u00f6hen: *\/\n#include &lt;unistd.h&gt;  \/* pledge() *\/\n#include &lt;err.h&gt;     \/* err() *\/\n#endif\n\nint main(void) {\n#ifdef __OpenBSD__\n    if (-1 == pledge(\"stdio\", NULL)) {\n        \/* Wir wollen nicht zu viele Befugnisse! *\/\n        err(EXIT_FAILURE, \"pledge\");\n    }\n#endif\n\n    \/* In der Umgebungsvariablen HTTP_ACCEPT_LANGUAGE\n     * stehen die Browsersprachen des Besuchers (weiter-\n     * geleitet per FastCGI):\n     *\/\n    const char* curr_language = getenv(\"HTTP_ACCEPT_LANGUAGE\");\n    bool is_en = false;\n\n    if (curr_language != NULL) {\n        \/* is_en auf \"true\" setzen, falls die ersten zwei\n         * Zeichen \"en\" sind und die Sprache nicht NULL\n         * (also der Browser des Besuchers nicht schweigsam)\n         * ist:\n         *\/\n        is_en = strncmp(curr_language, \"en\", 2) == 0;\n    }\n\n    \/* HTTP-Statuscodes ausgeben: *\/\n    puts(\"Status: 200 OK\\r\");\n    puts(\"Content-Type: text\/html\\r\");\n    puts(\"\\r\");\n\n    \/* Es folgt die eigentliche Website. *\/\n    puts(\" !doctype html&gt;\");\n    puts(\"<html><head>\");\n    puts(\"    <title>Sind wir schon verloren?<\/title>\");\n    puts(\"  <\/head>\");\n    puts(\"  <body>\");\n    puts(\"    <h1>\");\n\n    \/* Falls is_en \"true\" ist, gib \"Yes\" aus, sonst \"Ja\": *\/\n    if (is_en) {\n        puts(\"Yes\");\n    }\n    else {\n        puts(\"Ja\");\n    }\n\n    \/* Der Rest der Seite: *\/\n    puts(\"    <\/h1>\");\n    puts(\"  <\/body>\");\n    puts(\"\");\n\n    return(EXIT_SUCCESS);\n}<\/html><\/pre>\n<p>Die\u00adses Script kann jetzt zum Bei\u00adspiel als <tt>website.c<\/tt> gespei\u00adchert und anschlie\u00ad\u00dfend mit Open\u00adBS\u00adDs C\u2011Compiler zu einem Pro\u00adgramm gemacht wer\u00adden; ich emp\u00adfeh\u00adle die Akti\u00advie\u00adrung von War\u00adnun\u00adgen und Opti\u00admie\u00adrun\u00adgen sowie sta\u00adti\u00adscher Kom\u00adpi\u00adlie\u00adrung, damit kei\u00adne exter\u00adnen Abh\u00e4n\u00adgig\u00adkei\u00adten bei pl\u00f6tz\u00adli\u00adchem Aus\u00adfall die Funk\u00adti\u00adons\u00adf\u00e4\u00adhig\u00adkeit ein\u00adschr\u00e4n\u00adken k\u00f6n\u00adnen:<\/p>\n<pre>cc -static -Wall -O3 -o website website.c<\/pre>\n<p>Ein ein\u00adfa\u00adcher Auf\u00adruf des Pro\u00adgramms <tt>web\u00adsite<\/tt> gibt jetzt, wenn alles geklappt hat, den Sta\u00adtus\u00adhea\u00adder sowie den deutsch\u00adspra\u00adchi\u00adgen (da <tt>HTTP_ACCEPT_LANGUAGE<\/tt> lokal <em>nat\u00fcr\u00adlich<\/em> nicht exi\u00adstiert) HTML-Code aus. Als n\u00e4ch\u00adstes m\u00fcs\u00adsen wir nur noch den Web\u00adser\u00adver kon\u00adfi\u00adgu\u00adrie\u00adren. Falls ihr bis\u00adher <tt>nginx<\/tt> benutzt habt, ist es sinn\u00advoll, ihn zu deak\u00adti\u00advie\u00adren, bevor der <tt>httpd<\/tt> gestar\u00adtet wird. Au\u00dfer\u00addem soll\u00adte <tt>slow\u00adc\u00adgi<\/tt>, die <a href=\"http:\/\/man.openbsd.org\/slowcgi.8\">auf das Wesent\u00adli\u00adche redu\u00adzier\u00adte<\/a> Fast\u00adC\u00adGI-Imple\u00admen\u00adtie\u00adrung von Open\u00adBSD, akti\u00adviert wer\u00adden:<\/p>\n<pre># rcctl stop nginx\n# rcctl disable nginx\n# rcctl enable slowcgi\n# rcctl start slowcgi<\/pre>\n<p>Jetzt folgt der letz\u00adte Schritt: Beim Auf\u00adruf von <em>Sind-wir-schon-verloren.net<\/em> soll der <tt>httpd<\/tt> die Aus\u00adga\u00adbe des oben geschrie\u00adbe\u00adnen Fast\u00adC\u00adGI-Pro\u00adgramms zur\u00fcck\u00adge\u00adben. Es ist nicht damit getan, den Ser\u00adver <em>auf das Ver\u00adzeich\u00adnis zei\u00adgen<\/em> zu las\u00adsen, denn mit Bin\u00e4r\u00adda\u00adten kann er hier nichts anfan\u00adgen. Ein Ein\u00adtrag in eurer <tt>\/etc\/httpd.conf<\/tt> schafft Abhil\u00adfe:<\/p>\n<pre>ext_addr=\"egress\"\n\nserver \"sind-wir-schon-verloren.net\" {\n    # Der Server soll sich mit und ohne \"www\" gleich verhalten\n    alias \"www.sind-wir-schon-verloren.net\"\n    listen on $ext_addr port 80\n\n    # Der Aufruf \"zeigt\" direkt auf das FastCGI-Script:\n    root \"\/pfad\/zu\/eurem\/programm\"\n\n    # FastCGI aktivieren:\n    fastcgi socket \"\/run\/slowcgi.sock\"\n}<\/pre>\n<p>Ein beherz\u00adtes \u2013 falls noch nicht gesche\u00adhen \u2013 Akti\u00advie\u00adren von <tt>httpd<\/tt> und einen Neu\u00adstart (<tt>rcctl restart httpd<\/tt>) des Dae\u00admons sp\u00e4\u00adter ist eure Web\u00adan\u00adwen\u00addung wie\u00adder von au\u00dfen erreich\u00adbar, als w\u00e4re sie nie weg gewe\u00adsen \u2013 sie ben\u00f6\u00adtigt nur kei\u00adne zus\u00e4tz\u00adli\u00adchen Pake\u00adte mehr. Da nun alles wie gew\u00fcnscht funk\u00adtio\u00adniert, k\u00f6n\u00adnen wir schlie\u00df\u00adlich unse\u00adren jetzt nur noch unn\u00f6\u00adtig Platz ver\u00adschwen\u00adden\u00adden <tt>nginx<\/tt>-Ser\u00adver und die PHP-Instal\u00adla\u00adti\u00adon ent\u00adfer\u00adnen. Dabei soll\u00adte dar\u00adauf geach\u00adtet wer\u00adden, dass kei\u00adne <em>alten<\/em> PHP-Modu\u00adle \u00fcbrig blei\u00adben, wes\u00adhalb eine vor\u00adhe\u00adri\u00adge Auf\u00adli\u00adstung der instal\u00adlier\u00adten PHP-Tei\u00adle rat\u00adsam ist:<\/p>\n<pre># pkg_info | grep php\n# pkg_delete php-fpm nginx<\/pre>\n<p>M\u00f6g\u00adli\u00adcher\u00adwei\u00adse bit\u00adtet <tt>pkg_delete<\/tt> euch nun dar\u00adum, \u00fcbrig geblie\u00adbe\u00adne Kon\u00adfi\u00adgu\u00adra\u00adti\u00adons\u00adver\u00adzeich\u00adnis\u00adse zu l\u00f6schen. Das k\u00f6nnt ihr gefahr\u00adlos tun. Schaut auch in eurer <tt>\/etc\/rc.conf.local<\/tt> nach, ob <tt>nginx<\/tt> und <tt>php-fpm<\/tt> noch in euren Start\u00adscripts auf\u00adtau\u00adchen.<\/p>\n<p>Fer\u00adtig!<\/p>\n","protected":false},"excerpt":{"rendered":"<p>Unter \u201eSin\u00adg\u00adle-Ser\u00ad\u00adving Sites\u201c ver\u00adsteht man gemein\u00adhin Web\u00adsites wie IsItChristmas.com, WhatIsMyIP.org und purple.com, die als Gegen\u00adent\u00adwurf zu infor\u00adma\u00adti\u00adons\u00ad\u00fcber\u00adla\u00adde\u00adnen Web\u00adpor\u00adta\u00adlen meist genau eine ein\u00adzi\u00adge Fra\u00adge beant\u00adwor\u00adten. Es gibt in der Regel kei\u00adne Unter\u00adsei\u00adten, kei\u00adne ech\u00adte Inter\u00adak\u00adti\u00advi\u00adt\u00e4t und auch sonst sind sol\u00adche Web\u00adsites sehr ange\u00adnehm anzu\u00adse\u00adhen. Meist ist so eine Web\u00adsite schlicht in sta\u00adti\u00adschem HTML geschrie\u00adben wor\u00adden, denn \u2026<\/p>\n<p><a href=\"https:\/\/tuxproject.de\/blog\/2016\/07\/dynamische-single-serving-sites-mit-openbsd-bordmitteln-erstellen\/\" class=\"more-link\">\u2018Dyna\u00admi\u00adsche Sin\u00adg\u00adle-Ser\u00ad\u00adving Sites mit Open\u00adBSD-Bor\u00add\u00ad\u00admit\u00adteln erstel\u00adlen\u2019 wei\u00adter\u00adle\u00adsen \u00bb<\/a><\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"wp_typography_post_enhancements_disabled":false,"activitypub_content_warning":"","activitypub_content_visibility":"","activitypub_max_image_attachments":3,"activitypub_interaction_policy_quote":"anyone","activitypub_status":"","footnotes":""},"categories":[19],"tags":[],"series":[],"class_list":["post-11579","post","type-post","status-publish","format-standard","hentry","category-nerdkrams"],"share_on_mastodon":{"url":"","error":""},"wp-worthy-pixel":{"ignored":false,"public":null,"server":null,"url":null},"wp-worthy-type":"normal","_links":{"self":[{"href":"https:\/\/tuxproject.de\/blog\/wp-json\/wp\/v2\/posts\/11579","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/tuxproject.de\/blog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/tuxproject.de\/blog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/tuxproject.de\/blog\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/tuxproject.de\/blog\/wp-json\/wp\/v2\/comments?post=11579"}],"version-history":[{"count":0,"href":"https:\/\/tuxproject.de\/blog\/wp-json\/wp\/v2\/posts\/11579\/revisions"}],"wp:attachment":[{"href":"https:\/\/tuxproject.de\/blog\/wp-json\/wp\/v2\/media?parent=11579"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/tuxproject.de\/blog\/wp-json\/wp\/v2\/categories?post=11579"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/tuxproject.de\/blog\/wp-json\/wp\/v2\/tags?post=11579"},{"taxonomy":"series","embeddable":true,"href":"https:\/\/tuxproject.de\/blog\/wp-json\/wp\/v2\/series?post=11579"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}