Automatisierte Fehlerseiten mit Route53 und S3

Es darf nicht passieren - und dann es passiert doch. Selbst die am besten durchdachte Website ist irgendwann einmal offline. Mögliche Gründe dafür sind vielfältig: Ausfälle beim Hosting-Provider, Probleme mit der Internet-Anbindung bei selbst gehosteten Projekten, Software-Probleme mit Webserver oder Datenbank oder auch einfach nur menschliches Versagen.

Im besten Fall erhält der geneigte Website-Besucher in so einem Fehlerfall eine schön designte Fehlerseite, auf der man sich für die auftretenden Probleme aufrichtig entschuldigt und empfiehlt, doch später wieder vorbei zu schauen.

Mit etwas Logik und Programmieraufwand lassen sich solche Fehlerseiten natürlich innerhalb der eigenen Webumgebung realisieren. Aber was ist, wenn selbst diese nicht mehr ausgeliefert werden können? Dann erhält der Besucher vielleicht einfach eine kryptische Fehlermeldung des CMS oder er wartet frustiert auf die Timout-Meldung seines Browsers, der den Webserver nicht erreichen kann.

Mit einer Kombination aus Amazons Route53 und dem Amazon S3-Cloudspeicherservice lassen sich für solche Fehlerszenarien robuste Fehlerseiten zu sehr geringen Kosten realisieren.

Der Ansatz


Route53 ist der DNS-Service von Amazon. Dieser bietet in Kombination mit Health-Checks die Möglichkeit, DNS-Einträge bei Ausfall eines Servers auf einen sekundären Server umleiten zu lassen. Wenn also der primäre Webserver nicht wie gewünscht funktioniert, werden die anfragenden Clients per DNS-Failover auf die Adresse umgeleitet, auf der die Fehlerseite gehostet ist.

Die Fehlerseite sollte möglichst unabhängig von der eigenen Infrastruktur gehostet werden. Mit Amazon S3 - eigentlich ein Speicherdienst für die Cloud - lassen sich statische Websites komplett in der Cloud hosten.

Statische Fehlerseite auf Amazon S3


Zuerst müssen wir die Dateien der vorbereiteten statischen Fehlerseite in einem S3 Bucket ablegen. Dabei ist zu beachten, dass der Bucket den gleichen Namen erhält wie die Domäne, welche wir im Fehlerfall bedienen wollen. In meinem Beispiel lautet der Domainname - und damit der Name des Buckets "myexamplewebsite.com". Verwaltet werden die S3-Buckets über die AWS-Console unter https://console.aws.amazon.com/s3/

Im Beispiel kommen für die Fehlerseite 3 Dateien zum Einsatz: Die index.html für die eigentliche Fehlerseite, ein Logo als logo.png und für das Corporate-Design die style.css.

Dateien der statischen-Fehlerseite im S3-Bucket

Die Dateien für die statische Fehlerseite liegen jetzt sicher aufbewahrt in den Cloud-Systemen von Amazon. Im nächsten Schritt muss für den gerade erstellten Bucket das statische Hosting aktiviert werden. Das erfolgt über den Button "Properties" und dort über den Punkt "Static Website Hosting". Als Index-Dokument geben wir die gerade hochgeladene index.html an:

Aktivieren des statischen Hostings

Nachdem diese Änderungen gespeichert sind, sollte unsere neue Website unter dem angegebenen Endpoint-Namen (hier http://myexamplewebsite.com.s3-website-eu-west-1.amazonaws.com/) im Browser verfügbar sein. Wären da nicht die Berechtigungen:


Objekte als "public" markieren
Die Dateien, die wir in den Bucket geladen gaben, sind per Default nur von uns lesbar. Im einfachsten Falle helfen wir uns hier, indem wir die 3 statischen Elemente (index.html, logo.png und style.css) als "Public" markieren. Der entsprechende Punkt findet sich im Kontext-Menu jedes Objektes.

Sobald alle Objekte entsprechen freigegeben sind, ist die Website für die Außenwelt verfügbar. Interessant ist, dass die Website bereits jetzt nicht nur über die S3-Bucket-Adresse erreichbar ist (myexamplewebsite.com.s3-website-eu-west-1.amazonaws.com), sondern auch über den Website-Namen selber (myexaplewebsite.com). Um das zu testen genügt ein kurzer statischer Eintrag in der lokalen Hosts-Datei und der anschließende Aufruf der Website im Browser.



Die Fehler-Website ist jetzt fast fertig - eine Kleinigkeit gibt es jedoch noch zu bedenken: Die Fehlerseite soll ja per DNS-Failover angesprochen werden. Angenommen den Fall, ein Benutzer möchte gerne die Seite
"http://myexample.com/neues/artikel.html" aufrufen. Im Fehlerfall soll unser DNS auf unsere neue S3-Website verweisen - der Browser wird dann also versuchen, das Objekt "artikel.html" unterhalb des Ordners "neues" in unserem S3-Bucket abzurufen. Das wird offensichtlich zu Fehlermeldungen führen.

Am schnellsten kann man dieses Problem lösen, indem man in den Eigenschaften unseres Buckets die index.html-Datei sowohl als "Index Document" als auch als "Error Document" verwendet.

Eine Alternative dazu bietet das gezielte Umleiten über die sogenannten "Redirection Rules". Hier kann kann man dann - ganz Suchmaschinen freundlich - einzelne Requests bewusst per temporärem Redirect umleiten. Folgender Regelsatz leitet alle "403" und "404" Status-Codes unseres S3-Buckets auf die Default-Seite um:
<RoutingRules>
  <RoutingRule>
    <Condition>
      <HttpErrorCodeReturnedEquals>403</HttpErrorCodeReturnedEquals>
    </Condition>
    <Redirect>
      <HostName>http://myexamplewebsite.com/</HostName>
      <ReplaceKeyWith/>
      <HttpRedirectCode>302</HttpRedirectCode>
    </Redirect>
  </RoutingRule>
  <RoutingRule>
    <Condition>
      <HttpErrorCodeReturnedEquals>404</HttpErrorCodeReturnedEquals>
    </Condition>
    <Redirect>
      <HostName>http://myexamplewebsite.com/</HostName>
      <ReplaceKeyWith/>
      <HttpRedirectCode>302</HttpRedirectCode>
    </Redirect>
   </RoutingRule>
</RoutingRules>

Eine ausführliche Dokumentation zu den Redirect-Regeln findet sich hier.

DNS-Failover mit Route53 und Health-Checks


Wir haben jetzt also eine Fehlerseite, die sicher in der Amazon-S3-Cloud liegt und bei Bedarf jeden beliebigen URL-Aufruf auf unsere Domain mit einer netten Fehlerseite beantworten kann. Was uns jetzt noch fehlt, ist die Erkennung des Fehlerzustandes und das Realisieren des DNS-Failovers. Beides lässt sich sehr einfach und ohne eigenen Programmieraufwand mit Amazon Route53 realisieren.

Das Einrichten einer eigenen DNS-Zone mit den entsprechenden Resource-Records habe ich bereits hier beschrieben: robert-wohlfahrt.de/2013/06/route-53-dns-management-in-der-cloud.html

Health-Checks


Zusätzlich zur Konfiguration unserer Zone erstellen wir uns einen Health-Check. Das ist eine einfache Regel, die beschreibt, wie Route53 den Ausfall unserer primären Website erkennt. In der Regel hinterlegen wir hier einfach, welche Website auf welchem Host aufgerufen werden soll. Ein Health-Check gilt dann als erfolgreich, wenn der Webserver auf die Anfrage mit einem HTTP-Status-Code aus den Bereichen 2xx oder 3xx antwortet. 

Die Konfiguration der Health-Checks erfolgt über die Route53-Console -> "Health Checks" -> "Create Health Check":
Angaben für einen neuen Health-Check
Alternativ zur Angabe von URL-Informationen können Health-Checks auch als Verbindungsversuche auf dedizierte TCP-Ports konfiguriert werden.

Nach dem Speichern werden mehrere Amazon-Server in regelmäßigen Abständen (alle 30 Sekunden) versuchen, die angebenene URL zu erreichen. Sollte die entsprechende Anfrage drei mal  hintereinander fehlschlagen, wird die Ressource als "unhealthy" gekennzeichnet. Sollten später 3 aufeinanderfolgende Versuche erfolgreich sein, wird die Ressource wieder als "healthy" markiert.
Erst wenn _alle_ Health-Checker eine Ressource als "unhealthy" eingestuft haben, gilt der Health-Check dieser Ressource als fehlgeschlagen und das DNS-Failover kann eingeleitet werden.

Route53 - Failover-Ressource - primary
Route53 - Failover-Ressource - primary

Konfiguration einer DNS-Failover-Ressource - primary


Um auf die konfigurierten Health-Checks mit einem DNS-Failover reagieren zu können, konfigurieren wir den Standard-A-Record unserer Website mit der "Routing Policy" "Failover". Unseren Health-Check verknüpfen wir unter dem Punkt "Check to Associate". 

Mit dieser Konfiguration haben wir einen Resource-Record erzeugt, der nur dann ausgeliefert werden soll, wenn der zugeordnete Health-Check die zugeordnete Ressource als "gesund" einstuft.

Konfiguration einer DNS-Failover-Ressource - secondary


Für den Fehlerfall konfigurieren wir den A-Record für unsere Website-Adresse ein zweites mal. Als "Inhalt" des Resource-Records konfigurieren wir als Alias die Adresse unseres S3-Buckets (ohne den Bucketnamen). Dieser Alias wird in der Drop-Down-Liste ("unter S3 Website Endpoints") automatisch mit angeboten und muss nur noch ausgewählt werden. Im Gegensatz zu der "primary"-Ressource erhält die secondary-Recource keinen zugeordneten Health-Check - sie soll ja gerade dann ausgeliefert werden, wenn der Health-Check fehlgeschlagen ist.

Route53 - Failover-Ressource - secondary
Route53 - Failover-Ressource - primary

Ab jetzt ist unsere Failover-Website funktional. Seit der Konfiguration des Health-Checks zeigen die Webserver-Logs regelmäßige Kontakte der Amazon-Check-Server. Um die Konfiguration zu testen, könnte man in einer stillen Stunde einfach mal den Webserver-Dienst beenden. Nachdem 3 aufeinanderfolgende Health-Checks fehlgeschlagen sind (was nach knapp 2 Minuten der Fall sein sollte), Antworten die Route53-DNS-Server auf Anfragen nach unserer Website mit der Adresse unserer S3-Website. Ist der Webserver wieder verfügbar, landen Zugriffe automatisch wieder auf unserem produktiven Webserver.
Damit der Übergang möglichst reibungslos funktioniert, sollten die TTLs der betreffenden Resource-Records nicht allzu hoch eingestellt sein.

Und was kostet das ganze?


Die Kosten für die oben beschriebene Konfiguration liegen in der Regel bei unter 2 US-Dollar / Monat: 

Der benötigte S3-Speicher (bei Belegung bis 1GB, bis zu 1.000 Uploads und 10.000 Downloads) wird mit ca. 10 Cent / Monat zu Buche schlagen. Eine gehostete S3-Zone wird mit 0,50$ / Monat berechnet, für eine Million DNS-Abfragen hätte Amazon gerne auch noch einmal 0,50$. Health-Checks, die auf Systeme ausgerichtet sind, die nicht unter AWS gehostet werden, stellt Amazon mit 0,75$/Monat in Rechnung. 

In Summe also ca. 1,85$ / Monat (Stand 4. Juli 2013).