Cloud-Geschichten – Teil 5 – Hosting mit Object Storage Service (OSS)

In diesem Teil möchte ich kurz auf das Hosting von statischen Webseiten mit Hilfe der Alibaba Cloud bzw. dem Object Storage Service (OSS) eingehen. Nachdem im letzten Teil die meisten Vorbereitungen getroffen worden sind und insbesondere der Prozess des Hochladens der statischen Dateien thematisiert wurde, sind nun nur noch wenige Konfigurationsschritte zu erledigen.

Einrichtung von Object Storage Service für Website-Hosting

Das Bucket namens „geschkenet-site“ wurde bereits eingerichtet und muss zur Verwendung von statischen Webseiten konfiguriert werden. Dazu dient der Dialog „Basic Settings“.

Cloud-Geschichten - Teil 5 - Hosting mit Object Storage Service (OSS) 1

Wie hier zu erkennen ist, wird als „Default Homepage“ eine Datei „index.html“ eingestellt. Das bedeutet nichts anderes, als dass bei einem Zugriff auf die Startseite, d.h. „http://<domainname>.<tld>“, etwa http://www.geschke.net, an den Nutzer die Datei namens „index.html“ ausgeliefert wird. Im Unterschied zur Verwendung von üblichen Web-Servern wie Apache oder Nginx gilt diese Einstellung im Alibaba Cloud OSS jedoch nur für das Root-Verzeichnis, oder auch Document Root, also das Wurzelverzeichnis der Site. Man mag bereits ahnen, dass dies nicht unproblematisch ist, dazu gleich mehr.

Des Weiteren kann eine Standard-Fehlerseite für nicht gefundene Seiten eingerichtet werden, darauf habe ich im Rahmen des Tests zunächst verzichtet. Die Konfiguration ist nur noch mit „Save“ zu bestätigen, womit der erste Schritt erledigt wäre. Dass die ACL-Zugriffsrechte auf „Public Read“ gesetzt werden müssen, versteht sich von selbst, dies wurde beim Anlegen bereits berücksichtigt. Schließlich sollen die Seiten für die Öffentlichkeit erreichbar sein.

Nach dem Hochladen (siehe Cloud-Geschichten – Teil 4 – Mit RAM und CLI in OSS) der Dateien könnte sich eine Verzeichnisstruktur wie folgt zeigen:

Cloud-Geschichten - Teil 5 - Hosting mit Object Storage Service (OSS) 2

Dabei wurden alle Dateien und Verzeichnisse, die Hugo im „public“-Verzeichnis generiert hat, in das Bucket von OSS hochgeladen. Der Zugriff würde bereits jetzt funktionieren, und zwar unter der URL, die als „Bucket Domain Name“ für „Internet Access“ in der Übersicht des Buckets in der Admin-UI angegeben ist – das wäre für den konkreten Fall „http://geschkenet-site.oss-eu-central-1.aliyuncs.com/“.

Eine (Sub-)Domain muss her

Da niemand diese etwas sperrigen bzw. langen URLs eingeben möchte, kann ein selbst gewählter Domainname dafür genutzt werden. Falls man noch keinen Domainnamen besitzt, kann die Registrierung auch bei Alibaba Cloud erfolgen. Für das Beispiel wollte ich jedoch meine Domain „geschke.net“ einsetzen, wobei für den ersten Test die Subdomain „cl.geschke.net“ genutzt werden sollte. Wichtig ist dabei, dass man Zugriff auf die DNS-Konfiguration hat, entweder auf eigene DNS-Server oder aber über den Provider, über den die Domain registriert worden ist.

In einem ersten Schritt muss Alibaba Cloud den eigenen (Sub-)Domainnamen mit dem jeweiligen OSS-Bucket verknüften. Diese Einstellung kann im Reiter „Domain Names“ mit dem Button „Bind Self-Hosted Domain Name“ vorgenommen werden:

Cloud-Geschichten - Teil 5 - Hosting mit Object Storage Service (OSS) 3

Auf das Content Delivery Network (CDN) wollte ich zunächst verzichten, daher blieb die Option deaktiviert. Dass die DNS-Einstellungen bzw. der so genannte CNAME nicht durch Alibaba Cloud automatisch konfiguriert werden konnte, liegt daran, dass die Domain nicht bei Alibaba Cloud registriert worden ist.

Nach dem Speichern wird einem der nächste Schritt recht anschaulich erklärt:

Cloud-Geschichten - Teil 5 - Hosting mit Object Storage Service (OSS) 4

Der so genannte CNAME in der DNS-Konfiguration ist ein Aliasname auf einen anderen Domainnamen, meist ein A-Record. Es wird somit nicht direkt eine IP-Adresse eingetragen, sondern nur ein Verweis auf einen anderen Domainnamen. Damit kann die Zuweisung der IP-Adresse für den Domainnamen, auf den der CNAME verweist, geändert werden, ohne dass der CNAME selbst erneut angepasst werden muss. Insofern heißt es nun, in die DNS-Einstellungen für die Domain zu gehen und den Eintrag vorzunehmen. In meinen DNS-Servern sieht dies wie folgt aus:

Cloud-Geschichten - Teil 5 - Hosting mit Object Storage Service (OSS) 5

Natürlich sind DNS-Daten öffentlich und können jederzeit abgefragt werden, das „Schwärzen“ oder vielmehr die beiden grauen Rechtecke dienen somit nur zur Verdeutlichung, dass nur dieser eine Eintrag vorgenommen werden muss. Nach der Aktualisierung der DNS-Daten steht die Website somit auch unter der URL http://cl.geschke.net zur Verfügung.

Jedoch hatte ich Hugo beim Generieren diese Domain im ersten Versuch noch nicht mitgeteilt, weshalb die CSS- und JavaScript-Dateien nicht gefunden wurden und die Site entsprechend entstellt ausgesehen hat. Aber dies war schnell geändert:

baseURL = "http://cl.geschke.net/"

Nach dem erneuten Hugo-Lauf und anschließendem Hochladen wurden auch alle dazu gehörten CSS- und JavaScript-Dateien gefunden.

Nun könnte doch alles prima sein, oder? Naja, fast. Denn es ergaben sich schnell zwei Probleme, und zwar zum einen die Frage nach verschlüsselter Übertragung per https und zum anderen ein Problem mit der Site-Struktur selbst bzw. dem Zugriff auf einzelne Dateien.

OSS und https

Das erste ist einfacher lösbar, daher zunächst zur Transportverschlüsselung https. Spätestens seit der Initiative von Let’s Encrypt hat sich die Verbreitung von https stark erhöht, und dank der kostenlosen Zertifikate stellt der Kostenfaktor ebenfalls kein Hindernis mehr dar. So sind auch die statischen Webseiten unter der OSS-URL per https erreichbar (z.B. https://geschkenet-site.oss-eu-central-1.aliyuncs.com/), nur möchte man eine solche URL wie bereits angedeutet eher nicht verwenden. Insofern muss es eine Möglichkeit geben, für den eigenen Domainnamen ein Zertifikat einzurichten. Tatsächlich sieht OSS genau dies vor, und zwar auf denkbar einfache Weise mittels Upload des SSL-Zertifikats.

Cloud-Geschichten - Teil 5 - Hosting mit Object Storage Service (OSS) 6

Des Weiteren kann man wiederum Cloud-Dienste von Alibaba zur Zertifikatserstellung nutzen, was jedoch verständlicherweise nicht kostenlos ist. Nun könnte man anmerken, dass leider keine Let’s-Encrypt-Integration vorhanden ist, so dass sich SSL-Zertifikate kostenlos nutzen lassen. Das ist zwar richtig, wäre meines Erachtens aber Jammern auf hohem Niveau. Andere Cloud-Dienstleister sind wesentlich restriktiver, teurer oder es bedarf der Nutzung des ebenfalls angebotenen CDN-Dienstes, um überhaupt SSL-Zertifikate einbinden zu können. Insofern zeigt sich Alibaba Cloud hier pragmatisch und – unter der Voraussetzung, dass sich auch kostenfreie Zertifikate hochladen ließen – ebenso kostengünstig.

Leider ist die Nutzung von Let’s-Encrypt-Zertifikaten – nunja, sagen wir mal – etwas eigen… Die Tools zur automatischen Generierung sind einerseits einfach, sofern man sich an den vorgegebenen Workflow hält, andererseits ist der Aufwand der klassischen bzw. manuellen Generierung etwas höher. Ansonsten bleibt noch der Weg über von Providern angebotene Zertifikate, deren Laufzeit dann auch nicht auf drei Monate beschränkt ist. Persönlich nutze ich natürlich ebenfalls Let’s Encrypt und begrüße die Initiative sehr, aber so richtig Freude kommt erst bei Verwendung der automatisierten Prozesse auf. Ein Weg, manuell Zertifikate zu erstellen und zu deployen, beschreibt der Artikel „Tutorial: Securing your GitLab Pages with TLS and Let’s Encrypt„. Zwar passiert dies im Kontext von GitLab Pages, aber das Verfahren sollte sich leicht adaptieren lassen.

Damit wäre die erste Hürde theoretisch lösbar, ich bin dennoch für die Tests bei http (ohne „s“) geblieben, da ich zunächst die grundsätzliche Eignung feststellen wollte.

OSS vs. Web-Server

Ein schwierigeres Problem stellt jedoch die Site-Struktur dar bzw. die Funktionalität von OSS im Vergleich zum Hosting auf üblichen Web-Servern wie Apache oder Nginx.

Dafür gelten erst einmal folgende Grundannahmen: Es handelt sich um statische Seiten. Das heißt, es ist kein URL-Rewriting möglich, es existiert kein Frontend-Controller, der alle Requests entgegen nimmt und weiter verarbeitet, es gilt die Regel, dass eine Seite bzw. eine URL gleichzusetzen ist mit einer Datei, die auf dem Web-Server vorhanden ist und ausgeliefert werden kann.

Wobei – dies ist nicht ganz richtig, denn es gibt eine Ausnahme, und zwar die Index-Seiten. Jeder Web-Server besitzt eine Option, mit der Index-Seiten konfiguriert werden können. Wenn also ein Request eines Users ohne spezielle Angabe einer Datei erfolgt, d.h. ein Verzeichnis angesprochen wird (dies schließt auch das Document Root mit ein), dann wird der Web-Server versuchen, eine Datei wie index.html, index.htm oder index.php auszuliefern, die sich im jeweils angesprochenen Verzeichnis befindet. Web-Server lassen sich dahingehend konfigurieren, bei Nginx beispielsweise etwa wie folgt für eine interne Test-Domain:

server {
        listen 80; # default_server;
        #listen [::]:80 default_server ipv6only=on;

        root /vol/www/g1.geschke.net/htdocs;
        index index.php index.html index.htm;

        # Make site accessible from http://localhost/
        server_name g1.geschke.net g1;
[...]
}

Die Reihenfolge wird dabei ebenfalls festgelegt, es gilt für das Beispiel: Falls keine Datei index.php vorhanden ist, wird index.html ausgeliefert, danach index.htm, und erst wenn keine der genannten Dateien zu finden ist, wird je nach Konfiguration eine Fehlerseite (404, nicht gefunden) angezeigt, oder aber – heutzutage eher selten – der Verzeichnisinhalt als Liste.

Nun macht sich Hugo dieses Standard-Verhalten von Web-Servern bei der Generierung der Dateien und Verzeichnisse zunutze, um „schöne“ URLs zu erzeugen. Das heißt, dass auf Verzeichnisse mit darin liegender Datei index.html zurück gegriffen wird, anstatt einzelne Dateien zu generieren. Am besten lässt sich dies anhand eines kleinen Beispiels verdeutlichen. Im „content„-Verzeichnis von Hugo liegen die Quelldateien bzw. der Verzeichnisbaum, aus dem sich die Struktur und Inhalte der Web-Site ergeben. Für meine kleine Site ist gar nicht viel notwendig, daher sieht der Inhalt wie folgt aus:

-rw-rw-r-- 1 geschke geschke 56900 Jan 10 18:39 datenschutz.html
-rw-rw-r-- 1 geschke geschke  7256 Jan 10 18:39 feedback.html
-rw-rw-r-- 1 geschke geschke   324 Jan 10 18:39 impressum.md
-rw-rw-r-- 1 geschke geschke   859 Jan 10 18:39 _index.md
[...]

Die „Startseite“ wird durch die Datei _index.md repräsentiert, d.h. daraus entsteht die Datei index.html im Stammverzeichnis / Document Root. Darüber hinaus gibt es die obligatorischen Impressum- und Datenschutz-Seiten sowie ein Feedback-Formular. Bei den Quellen handelt es sich somit ausschließlich um Dateien im Hauptverzeichnis, auf eine weiter gehende Verschachtelung habe ich angesichts dieser wenigen Inhalte verzichtet.

Hugo möchte jedoch „schöne“ URLs erzeugen, was nicht nur Tipparbeit bei direkter Eingabe von URLs spart, sondern auch der Suchmaschinenoptimierung (SEO) zugute kommt – zumindest gerüchteweise. Das Ergebnis der Generierung ist im „public„-Verzeichnis zu finden:

.
├── datenschutz
│   └── index.html
├── feedback
│   └── index.html
[...]
├── impressum
│   └── index.html
├── index.html
[...]
└── vernetzt
    └── index.html

Hugo erzeugt neben den hier dargestellten Verzeichnissen ebenso diejenigen, in denen CSS- und JavaScript-Dateien Platz finden – aus Gründen der Übersichtlichkeit habe ich die obige Ausgabe von „tree“ jedoch gekürzt.

Wie zu erkennen ist, befindet sich nur die „Startseite“ als index.html in der ersten Verzeichnisebene, d.h. dem Document Root. Für alle weiteren „Seiten“ wurden Verzeichnisse angelegt, in dem sich jeweils der Inhalt in der index.html-Datei wiederfindet. Dank des Standard-Verhaltens von Web-Servern sind damit URLs möglich wie http://www.geschke.net/impressum (wobei es eigentlich korrekt mit trailing slash http://www.geschke.net/impressum/ lauten müsste, aber je nach Webserver-Konfiguration wird beides akzeptiert). Man erspart sich also das als „weniger schön“ empfundene „.html“, das auf einzelne Dateien hinweist.

Nun ist OSS jedoch kein Standard-Webserver, und angesichts der Kennung „server: AliyunOSS“ im Response-Header wird auch nicht viel klarer, welche Technologie Alibaba Cloud hier verwendet. Genau darin liegt das Problem, denn das Verhalten von OSS ist bei Verzeichnissen unterhalb des Document Root ein völlig anderes und wird auch in der Dokumentation entsprechend beschrieben. Denn die Nutzung der index.html-Datei kann nur für das Document Root eingestellt werden. Wird nun versucht, auf ein Verzeichnis, etwa aus obigem Beispiel /impressum/ zuzugreifen, liefert OSS zwar keine Fehlermeldung, dafür aber die index.html-Seite aus dem Document Root (!) aus, also die Startseite. Der direkte Zugriff auf Dateien in Verzeichnissen ist jedoch möglich. Im Beispiel: Wenn man auf http://cl.geschke.net/datenschutz/ zugreift, wird der Inhalt von http://cl.geschke.net zurück gegeben. Dasselbe gilt für jeden Zugriff auf weitere Verzeichnisse, obwohl sich darin jeweils eine Datei index.html befindet. Hingegen lässt sich http://cl.geschke.net/datenschutz/index.html erreichen, dann erfolgt auch die Auslieferung des korrekten Inhalts, aber solche URLs will man sich nun wirklich nicht mehr antun…

Hugo bietet jedoch eine durchaus nutzbare Lösung, und zwar in Form einer Konfigurationsoption namens „uglyurls„. Dazu ist einfach folgendes in der config.toml zu setzen:

uglyurls = true

Nach der Generierung finden sich folgende Dateien im public-Verzeichnis:

.
├── datenschutz.html
├── feedback.html
├── impressum.html
├── index.html
[...]
└── vernetzt.html

Aus Gründen der Übersichtlichkeit sind CSS- und JavaScript- und sonstige Verzeichnisse wieder gekürzt. Hugo hat nun tatsächlich HTML-Dateien mit Endung .html generiert, was in URLs, etwa in Menüs, entsprechend berücksichtigt werden muss.

Nun heißt die Direktive jedoch nicht umsonst „uglyurls“, denn so richtig schön, modern und zeitgemäß wirken diese URLs nicht. Und eine Lösung gibt es tatsächlich nicht, ansonsten würde Alibaba Cloud dieses Verhalten, das man freilich für einen Fehler halten könnte, nicht auch noch ausführlich dokumentieren.

Fazit und Ausblick

Genau das Problem mit der Strukturierung der URLs bzw. dem Verhalten, beim Zugriff auf Verzeichnisse die Inhalte von index.html aus dem Document Root zurückzuliefern, hat mich davon abgehalten, OSS für das Hosting von statischen Webseiten zu verwenden. Zwar lässt sich mit Hugo diese Hürde umschiffen, aber dennoch bleibt dies ein Workaround, der mir nicht wirklich zusagt.

Nicht zuletzt können Web-Server wie Nginx oder Apache statische Seiten sehr schnell ausliefern – genau das ist ja gerade der Vorteil von fertigen, sich auf dem jeweiligen Speichermedium befindlichen Dateien. Und wenn es wider Erwarten doch einmal zu Engpässen kommen sollte, kann man immer noch ein Content Delivery Network verwenden – Alibaba Cloud bietet ein solches ebenfalls an. Nach all diesen Vorbereitungen, um statische Webseiten ganz modern in der Cloud zu hosten, erfolgt nun also der Schritt zurück. Natürlich könnte man nun wiederum den Elastic Compute Service von Alibaba Cloud nutzen, um sich virtuelle Server zu bauen, die dann mit Docker und so weiter… ja, könnte… Möglichkeiten und Wege gibt es meist viele, doch für das Hosting meiner kleinen Website habe ich dies erstmal als nicht sinnvoll abgehakt. Vielleicht ändert sich irgendwann auch das Verhalten von OSS, so dass Hosting sinnvoll betrieben werden kann. Bis dahin ließe sich OSS noch immer prima nutzen, um etwa CSS-, JavaScript-, Bilddateien etc. auszulagern, auf die jeweils direkt referenziert wird.

Der nächste Teil wird sich mit einem aus Entwickler-Sicht viel interessanteren Dienst beschäftigen, und zwar dem „serverless computing“, bei Alibaba Cloud „Function Compute“ genannt. Dann gibt es auch endlich mal wieder etwas Code zu sehen!

 

 

 

Schreibe einen Kommentar

Deine E-Mail-Adresse wird nicht veröffentlicht. Erforderliche Felder sind mit * markiert

Tags: