Nerdkrams
Dynamische Single-Serving Sites mit OpenBSD-Bordmitteln erstellen

Unter “Sin­gle-Serv­ing Sites” ver­ste­ht man gemein­hin Web­sites wie IsItChristmas.com, WhatIsMyIP.org und purple.com, die als Gege­nen­twurf zu infor­ma­tion­süber­lade­nen Web­por­tal­en meist genau eine einzige Frage beant­worten. Es gibt in der Regel keine Unter­seit­en, keine echte Inter­ak­tiv­ität und auch son­st sind solche Web­sites sehr angenehm anzuse­hen.

Meist ist so eine Web­site schlicht in sta­tis­chem HTML geschrieben wor­den, denn ser­ver­seit­ige Scripts sind eben­so über­flüs­sig wie jQuery oder andere Per­ver­sio­nen des Mod­er­nen. Was aber, wenn man dem Besuch­er etwa abhängig von sein­er Browser­sprache oder per Zufall­sal­go­rith­mus eine andere Ansicht präsen­tieren will? Natür­lich kön­nte man auf Javascript zurück­greifen; wer das aber nicht möchte, zum Beispiel, weil er sich nicht darauf ver­lassen möchte, dass der Besuch­er Javascript aktiviert hat und einen mit dem geschriebe­nen Code kom­pat­i­blen Brows­er benutzt, dem bleibt let­ztlich nur die Nutzung ser­ver­seit­i­gen Codes, etwa Perl oder PHP, übrig.

Nun gilt für Serv­er mehr noch als für einen Lap­top oder PC, dass jede zusät­zlich instal­lierte Soft­ware wegen möglich­er noch unent­deck­ter oder unko­r­rigiert­er Fehler ein poten­zielles Sicher­heit­srisiko birgt, wozu auch Skript­sprachen, Web­server­soft­ware und sog­ar Texte­d­i­toren zählen. Dazu kommt der Ressourcenhunger, den manch­er stack mit sich bringt: Benutzt man etwa die beliebte Kom­bi­na­tion aus dem Web­serv­er nginx und der Sprache PHP im FastC­GI-Modus (php-fcgi), ist es keine Sel­tenheit, dass auch im Leer­lauf diverse Prozesse an den Sys­tem­res­sourcen knab­bern.

Lässt sich eine solche Weban­wen­dung auch pro­gram­mieren, ohne den Serv­er unnötiger Last und Gefahren auszuset­zen? Nun, je nach Betrieb­ssys­tem stellt das tat­säch­lich kein Prob­lem dar, denn zum Beispiel OpenB­SD ver­fügt von Haus aus über einen brauch­baren Texte­d­i­tor (vi), einen FastC­GI unter­stützen­den Web­serv­er (httpd mit slow­c­gi) sowie einen C‑Compiler (cc). C mag nicht ger­ade eine beson­ders ein­steiger­fre­undliche Sprache sein, aber für ein biss­chen Tex­taus­gabe ist nicht viel Code nötig. Ich mach’ mal ein Beispiel.

Wir gehen im Fol­gen­den davon aus, dass wir eine beste­hende Web­site namens “Sind-wir-schon-verloren.net” haben, die bish­er aus einem unter OpenB­SD in einem nginx-Serv­er laufend­en PHP-Script beste­ht, das, wenn ein englis­chsprachiger Besuch­er es aufruft, “Yes”, son­st “Ja” aus­gibt.

<!doctype html>
<html>
  <head>
    <title>Sind wir schon verloren?</title>
  </head>
  <body>
    <h1><?php
      /* Browsersprache ermitteln: */
      if (substr($_SERVER["HTTP_ACCEPT_LANGUAGE"],0,2) == "en") {
          /* Aha, ein englischsprachiger Nutzer! */
          echo "Yes";
      }
      else {
          /* Aha, kein englischsprachiger Nutzer! */
          echo "Ja";
      }
    ?></h1>
  </body>
</html>

So weit, so ver­ständlich. PHP hat den Vorteil, dass man es ein­fach in beste­hende HTML-Seit­en inte­gri­eren kann und der Web­serv­er erledigt den Rest. Aber wir wollen ja Ressourcen sparen, also pro­gram­mieren wir das ganze Ding mal neu.

Wenn ihr Web­serv­er wie nginx oder lighttpd ein­set­zt, läuft PHP bei euch ver­mut­lich bere­its im FastC­GI-Modus. FastC­GI bedeutet im Wesentlichen, dass der Web­serv­er laufend einige Kopi­en von PHP im Spe­ich­er hält, die bei ein­er Anfrage schnell das gewün­schte Ergeb­nis berech­nen, hier also aus der Liste der Aufruf­vari­ablen die über­mit­telte Liste der unter­stützten Sprachen her­aus­suchen und die ersten zwei Zeichen dieser Liste, zum Beispiel “de” für Deutsch oder “en” für Englisch als Haupt­sprache, mit der Zeichen­kette “en” ver­gle­ichen. Das klingt nicht nur wie der wohlbekan­nte Schuss aus Kanonen auf Spatzen, es hat auch ähn­liche Kon­se­quen­zen. Dass PHP selb­st im Leer­lauf gele­gentlich CPU-Zeit für sich beansprucht, ist nur eine davon.

Warum also bei jedem Aufruf die ganze HTML-Seite neu kom­pilieren? Viel effizien­ter ist es doch, ein bere­its vorkom­piliertes Pro­gramm hin­ter dieses FastC­GI zu hän­gen. Damit diese wiederum zusät­zliche Soft­ware keinen Unsinn anstellt, kön­nen wir sie mit dem OpenB­SD-Befehl pledge() unter Kon­trolle bekom­men. Los geht’s!

Die C‑Version unser­er PHP-Seite sieht so aus:

/* Erst mal ein paar Funktionen nachladen: */
#include <stdlib.h>  /* Standardbibliothek */
#include <stdio.h>   /* puts() */
#include <string.h>  /* strncmp() */
#include <stdbool.h> /* bool */
#ifdef __OpenBSD__
/* Unter OpenBSD können wir mit pledge() die Sicherheit erhöhen: */
#include <unistd.h>  /* pledge() */
#include <err.h>     /* err() */
#endif
 
int main(void) {
#ifdef __OpenBSD__
    if (-1 == pledge("stdio", NULL)) {
        /* Wir wollen nicht zu viele Befugnisse! */
        err(EXIT_FAILURE, "pledge");
    }
#endif
 
    /* In der Umgebungsvariablen HTTP_ACCEPT_LANGUAGE
     * stehen die Browsersprachen des Besuchers (weiter-
     * geleitet per FastCGI):
     */
    const char* curr_language = getenv("HTTP_ACCEPT_LANGUAGE");
    bool is_en = false;
 
    if (curr_language != NULL) {
        /* is_en auf "true" setzen, falls die ersten zwei
         * Zeichen "en" sind und die Sprache nicht NULL
         * (also der Browser des Besuchers nicht schweigsam)
         * ist:
         */
        is_en = strncmp(curr_language, "en", 2) == 0;
    }
 
    /* HTTP-Statuscodes ausgeben: */
    puts("Status: 200 OK\r");
    puts("Content-Type: text/html\r");
    puts("\r");
 
    /* Es folgt die eigentliche Website. */
    puts("< !doctype html>");
    puts("<html>");
    puts("  <head>");
    puts("    <title>Sind wir schon verloren?</title>");
    puts("  </head>");
    puts("  <body>");
    puts("    <h1>");
 
    /* Falls is_en "true" ist, gib "Yes" aus, sonst "Ja": */
    if (is_en) {
        puts("Yes");
    }
    else {
        puts("Ja");
    }
 
    /* Der Rest der Seite: */
    puts("    </h1>");
    puts("  </body>");
    puts("</html>");
 
    return(EXIT_SUCCESS);
}

Dieses Script kann jet­zt zum Beispiel als website.c gespe­ichert und anschließend mit OpenB­S­Ds C‑Compiler zu einem Pro­gramm gemacht wer­den; ich empfehle die Aktivierung von War­nun­gen und Opti­mierun­gen sowie sta­tis­ch­er Kom­pilierung, damit keine exter­nen Abhängigkeit­en bei plöt­zlichem Aus­fall die Funk­tions­fähigkeit ein­schränken kön­nen:

cc -static -Wall -O3 -o website website.c

Ein ein­fach­er Aufruf des Pro­gramms web­site gibt jet­zt, wenn alles geklappt hat, den Sta­tushead­er sowie den deutschsprachi­gen (da HTTP_ACCEPT_LANGUAGE lokal natür­lich nicht existiert) HTML-Code aus. Als näch­stes müssen wir nur noch den Web­serv­er kon­fig­uri­eren. Falls ihr bish­er nginx benutzt habt, ist es sin­nvoll, ihn zu deak­tivieren, bevor der httpd ges­tartet wird. Außer­dem sollte slow­c­gi, die auf das Wesentliche reduzierte FastC­GI-Imple­men­tierung von OpenB­SD, aktiviert wer­den:

# rcctl stop nginx
# rcctl disable nginx
# rcctl enable slowcgi
# rcctl start slowcgi

Jet­zt fol­gt der let­zte Schritt: Beim Aufruf von Sind-wir-schon-verloren.net soll der httpd die Aus­gabe des oben geschriebe­nen FastC­GI-Pro­gramms zurück­geben. Es ist nicht damit getan, den Serv­er auf das Verze­ich­nis zeigen zu lassen, denn mit Binär­dat­en kann er hier nichts anfan­gen. Ein Ein­trag in eur­er /etc/httpd.conf schafft Abhil­fe:

ext_addr="egress"

server "sind-wir-schon-verloren.net" {
    # Der Server soll sich mit und ohne "www" gleich verhalten
    alias "www.sind-wir-schon-verloren.net"
    listen on $ext_addr port 80

    # Der Aufruf "zeigt" direkt auf das FastCGI-Script:
    root "/pfad/zu/eurem/programm"

    # FastCGI aktivieren:
    fastcgi socket "/run/slowcgi.sock"
}

Ein beherztes — falls noch nicht geschehen — Aktivieren von httpd und einen Neustart (rcctl restart httpd) des Dae­mons später ist eure Weban­wen­dung wieder von außen erre­ich­bar, als wäre sie nie weg gewe­sen — sie benötigt nur keine zusät­zlichen Pakete mehr. Da nun alles wie gewün­scht funk­tion­iert, kön­nen wir schließlich unseren jet­zt nur noch unnötig Platz ver­schwen­den­den nginx-Serv­er und die PHP-Instal­la­tion ent­fer­nen. Dabei sollte darauf geachtet wer­den, dass keine alten PHP-Mod­ule übrig bleiben, weshalb eine vorherige Auflis­tung der instal­lierten PHP-Teile rat­sam ist:

# pkg_info | grep php
# pkg_delete php-fpm nginx

Möglicher­weise bit­tet pkg_delete euch nun darum, übrig gebliebene Kon­fig­u­ra­tionsverze­ich­nisse zu löschen. Das kön­nt ihr gefahr­los tun. Schaut auch in eur­er /etc/rc.conf.local nach, ob nginx und php-fpm noch in euren Startscripts auf­tauchen.

Fer­tig!

Senfecke:

  1. Com­piliert mit musl-gcc ist das sta­tisch gelink­te Pro­gramm auch schön klein:
    ‑rwx—— 1 hardy hardy 5704 Jul 23 09:01 web­site*

    • Meines Wis­sens funk­tion­iert musl nicht unter OpenB­SD, zumin­d­est kon­nte ich bish­er keinen Hin­weis darauf find­en. Startet das Pro­gramm denn über­haupt?

      • Startet das Pro­gramm denn über­haupt?

        Natür­lich nicht mit Deinem Mulu-Mulu-BSD. Mit Lin­ux selb­stver­ständlich ja.

            • Tscha, taugt halt nix.

              Unter Lin­ux müsste man sich irgen­deines zusam­mengek­leck­erten Drit­tan­bi­eterservers (nginx oder so) bedi­enen und den pledge()-Aufruf aus dem Code ent­fer­nen, dann sollte es allerd­ings auch gehen.

              Nach­trag: Ich habe den Code oben mal geän­dert, jet­zt sollte er auch unter anderen Sys­te­men prob­lem­los funk­tion­ieren.

Comments are closed.

https://tuxproject.de/blog/wp-content/plugins/wp-monalisa/icons/smiley_emoticons_smilenew.gif  https://tuxproject.de/blog/wp-content/plugins/wp-monalisa/icons/smiley_emoticons_biggrin2.gif  https://tuxproject.de/blog/wp-content/plugins/wp-monalisa/icons/smiley_emoticons_sadnew.gif  https://tuxproject.de/blog/wp-content/plugins/wp-monalisa/icons/smiley_emoticons_eek.gif  https://tuxproject.de/blog/wp-content/plugins/wp-monalisa/icons/smiley_emoticons_shocked.gif  https://tuxproject.de/blog/wp-content/plugins/wp-monalisa/icons/smiley_emoticons_confusednew.gif  https://tuxproject.de/blog/wp-content/plugins/wp-monalisa/icons/smiley_emoticons_coolnew.gif  https://tuxproject.de/blog/wp-content/plugins/wp-monalisa/icons/smiley_emoticons_lol.gif  https://tuxproject.de/blog/wp-content/plugins/wp-monalisa/icons/smiley_emoticons_madnew.gif  https://tuxproject.de/blog/wp-content/plugins/wp-monalisa/icons/smiley_emoticons_aufsmaul.gif  https://tuxproject.de/blog/wp-content/plugins/wp-monalisa/icons/smiley_emoticons_seb_zunge.gif  https://tuxproject.de/blog/wp-content/plugins/wp-monalisa/icons/smiley_emoticons_blushnew.gif  https://tuxproject.de/blog/wp-content/plugins/wp-monalisa/icons/smiley_emoticons_frown.gif  https://tuxproject.de/blog/wp-content/plugins/wp-monalisa/icons/smiley_emoticons_twistedevil1.gif  https://tuxproject.de/blog/wp-content/plugins/wp-monalisa/icons/smiley_emoticons_twistedevil2.gif  https://tuxproject.de/blog/wp-content/plugins/wp-monalisa/icons/icon_mad.gif  https://tuxproject.de/blog/wp-content/plugins/wp-monalisa/icons/smiley_emoticons_rolleyesnew.gif  https://tuxproject.de/blog/wp-content/plugins/wp-monalisa/icons/smiley_emoticons_wink2.gif  https://tuxproject.de/blog/wp-content/plugins/wp-monalisa/icons/smiley_emoticons_idea2.gif  https://tuxproject.de/blog/wp-content/plugins/wp-monalisa/icons/smiley_emoticons_arrow2.gif 
mehr …
 

Erlaubte Tags:
<strong> <em> <pre> <code> <a href="" title=""> <img src="" title="" alt=""> <blockquote> <q> <b> <i> <del> <tt> <span style=""> <strike>

Datenschutzhinweis: Deine IP-Adresse wird nicht gespeichert. Details findest du hier.