Umziehen Part 5: Die Schmerzen mit dem SSL

Das Webseiten nur noch über HTTPS erreichbar sind ist mittlerweile eher die Regel denn die Ausnahme. Zeit, die alte Serie aus 2012 noch mal aufzugreifen, denn durch die Omnipräsenz von HTTPS kommen plötzlich neue Probleme ins Spiel die es vorher so noch nicht gab.

Das Szenario dürfte der Standard sein:
Man hat einen Webshop und betreibt diesen auf www.example.com. Für genau diese Domain besitzt man auch ein Zertifikat, evtl. sogar mit Extended Validation. Außerdem hat man noch, um Trittbrettfahrer abzuhalten, example.org und example.net registriert.
Und alles was nicht www.example.com ist leitet man entsprechend um. Das ist bei HTTP auch kein wirkliches Problem und über zwei Zeilen in der .htaccess zu lösen:

1
2
3
4
5
6
<IfModule mod_rewrite.c>
RewriteEngine On
 
RewriteCond %{HTTP_HOST} !^www.example.com$
RewriteRule ^(.*)$ http://www.example.com/$1 [L,R=301]
</IfModule>

Kommt jetzt HTTPS ins Spiel ist es vorbei mit der Einfachheit. Denn https://example.com/ und https://www.example.com/ sind technisch nun mal zwei verschiedene URLs, können völlig unterschiedliche Inhalte zeigen und brauchen für eine fehlerfreie Funktionsweise entsprechend für jede URL ein Zertifikat.
Safari und Firefox quittieren den Umleitungsversuch von https://example.com/ nach https://www.example.com/ mit dem Zertifikat von https://www.example.com/ korrekterweise mit einer Fehlermeldung – Chrome erstaunlicherweise nicht (IE und Edge wurden nicht getestet).

Die Kosten für das eigentlich unnötige Zertifikat können sich schnell aufsummieren, neben dem Zertifikat selbst (evtl. mit EV) braucht man unter Umständen nämlich auch noch eine weitere IP-Adresse, weil der Provider aus nicht nachvollziehbaren Gründen noch immer kein SNI unterstüzt.

Will man also allen Traffic ohne www-Prefix unabhängig von HTTP und HTTPS fehlerfrei umleitung brauch man eine Lösung und die Rettung kommt, mal wieder, von Uberspace. Denn dort gibt es SNI, IPv6 und Zertifikate von Let’s Encrypt. Man muss also nur einen Uberspace klicken, mit uberspace-add-domain die gewünschten Domains hinzufügen und dann für diese nach dieser Anleitung Zertifikate erzeugen. Dann stellt man nur noch die DNS-Einträge für die umzuleitenden URLs auf Uberspace um und leitet alles ohne Zertifikatsfehler richtig um. Die .htaccess ist quasi identisch zu der oben, nur dass das Umleitungsziel jetzt natürlich die HTTPS-URL ist.

1
2
3
4
5
6
<IfModule mod_rewrite.c>
RewriteEngine On
 
RewriteCond %{HTTP_HOST} !^www.example.com$
RewriteRule ^(.*)$ https://www.example.com/$1 [L,R=301]
</IfModule>

Bleibt noch die Frage: Braucht man das? Niemand dürfte das händisch falsch eingeben und dann an einer Fehlermeldung hängenbleiben. Nun, selbst der Fall dürfte hin und wieder vorkommen, aber es braucht nur jemand einen falschen Link zu setzen damit Besucher mit entsprechenden Fehlermeldungen konfrontiert werden. Und auch die Search Console von Google meckert das falsche Zertifikat an (man muss ja beide Properties anlegen um die bevorzugte Domain in den SERPs einstellen zu können). Um so unverständlicher, dass Chrome da einfach drüber „hinwegsieht“.

Umziehen Part 4: Richtiges Zertifikat für den Proxy

Beim Umzug des Erzgebirge-Palastes ist noch etwas aufgefallen, das ich bislang im Rahmen der Umzugsservice-Reihe noch nicht behandelt hatte:

Wenn die umzuziehende Seite (auch) unter https erreichbar ist muss der Proxy ebenfalls mit dem richtigen Zertifikat ausgestatt sein. Glücklich, wer noch eine IPv4-Adresse frei hat. Ansonsten hagelt es Fehlermeldungen. Bedenken sollte man auch, dass es hinter dem Proxy unverschlüsselt weitergeht, ein solches Vorgehen ist also nur wirklich angebracht, wenn man sich anschließend in einer vertrauenswürdigen Umgebung bewegt.

503: Statuscode bei Problemen

Nichts wirklich neues erzählen Tomer Honen und Kaspar Szymanski in Googles Webmaster-Zentrale zum Umgang mit geplanten Wartungszeiten einer Website, aber noch immer sieht man viel zu oft Seiten, die für jeden noch so unpassenden Fall einen Statuscode 200 ausliefern, deshalb will ich es auch hier noch einmal aufgreifen.

Denn nicht nur für den Fall, dass eine Seite nicht gefunden wurde oder jetzt unter einer anderen URL erreichbar ist gibt es Statuscodes, auch, dass eine Seite kurzzeitig einmal nicht erreichbar ist, regelt RFC 2616:

10.5.4 503 Service Unavailable
The server is currently unable to handle the request due to a temporary overloading or maintenance of the server.

Das ganze kann man mit php sehr einfach erreichen, indem man den folgenden Code an den Anfang der Seite setzt:

header("HTTP/1.1 503 Service Temporarily Unavailable");
header("Retry-After: Tue, 25 Jan 2011 15:00:00 GMT");
header("Connection: Close");

Retry-After und Connection-Feld sind dabei optional. In ersterem kann man eine Info mitgeben, wann der Spider wieder vorbeischauen soll. Dabei ist entweder ein absolutes Datum möglich oder eine Angabe in Sekunden. Connection sorgt dafür, dass die Verbindung nicht als persitent angesehen werden soll.

Während man bei geplanten Ausfallzeiten das ganze sehr gut vorbereiten und implementieren kann empfiehlt Google den Statuscode 503 für weitere Probleme, die sich nicht so leicht vorhersehen lassen, etwa Serverausfälle, Bandbreitenüberschreitungen oder auch Baustellenseiten. In jedem Fall empfiehlt es sich aber, die Seite darüber hinaus noch zu gestalten, um dem menschlichen Besucher eine Information zukommen zu lassen, was der Grund für den Ausfall ist und bis wann damit gerechnet werden kann, dass wieder alles funktioniert.

Denn außer der Information „geht nicht” transportieren solche Standardseiten normalerweise keine brauchbaren Informationen für den Besucher, wie man heute schön sieht, wenn man Teuxdeux aufruft:

Im Vergleich dazu noch unsere 503-Seite, die wir im vergangenen Jahr geschaltet haben, als Hetzner unseren Server auf einen Laster geladen und von Bayern nach Sachsen transportiert hat:

Umziehen Part 3: Mit mod_proxy von Server zu Server

In Teil 1 und 2 haben wir uns damit beschäftigt, wie man Browser und Suchmaschinen den Weg zu einer neuen Ressource weißt, wenn sich deren URL geändert hat. In diesem Teil geht es um den einfachen Umzug auf einen neuen Server.

Im Folgenden geht es ausschließlich um den Umzug eines Webauftritts von einem Server auf einen anderen. Prinzipiell ist das ganze auch bei Shared Hosting möglich, gewisse Dinge wie der Zugriff auf die hosts-Datei sind dabei aber unter Umständen nicht möglich. mod_proxy sollte installiert und aktiviert sein. Der Zugriff auf die DNS-Konfiguration ist Bedingung.

Mit steigenden Zugriffszahlen wachsen auch die Anforderungen an die Hardware. Gerade wenn in Spitzenzeiten die Antwortzeiten in den Keller gehen ist es Zeit, sich Gedanken über einen Serverumzug zu machen. Oder dieser Schritt steht turnusmäßig sowieso an, weil die aktuelle Hardware veraltet ist. Doch wie die Besucher problemlos auf die neue Maschine migrieren, wie verhindern, dass Zugriffe auf die alte und die neue Maschine zeitgleich stattfinden? Schließlich ist das DNS-System zwar robust, aber mitunter nicht sonderlich schnell.

Wir möchten also unseren aktuellen Webauftritt unter www.domain.de, der auf dem Server mit der IP 8.8.4.4 liegt, auf einen neuen Server mit der IP 8.8.8.8 umziehen.

Der erste Schritt ist das ‘Anlegen’ einer Subdomain im lokalen hosts-File am Arbeitsrechner. Diese findet sich auf unixoiden Betriebssystemen in /etc/hosts, unter Windows in C:WINDOWSsystem32driversetchosts und kann mit jedem beliebigen Texteditor bearbeitet werden. Dort fügen wir einen neuen Eintrag hinzu:

8.8.8.8     new.domain.de

Dieses Vorgehen hat gegenüber einem richtigen DNS-Eintrag den Vorteil, dass new.domain.de nur vom Arbeitsrechner aus erreichbar ist und man so auf gesonderte Sicherungsmaßnahmen am neuen Server verzichten kann, wie sie sonst nötig wären, um eine vorzeitige Indizierung der Inhalte durch Google zu verhindern. Hat man keinen Zugriff auf die hosts-Datei am alten Server muss dieser Eintrag unbedingt über das DNS-System erfolgen und sollte mit entsprechendem Vorlauf (mind. 48 Stunden) gemacht werden!

Auf dem neuen Server richtet man nun new.domain.de ein und transferiert den aktuellen Webauftritt vollständig auf die neue Maschine, kopiert also sowohl Dateien als auch Datenbankinhalte auf den neuen Server und passt, sofern erforderlich, die Konfigurationsdateien an. Anschließend testet man alles auf Herz und Nieren.

Das Logfile zu Hilfe nehmend, um den idealen Transferzeitpunkt zu ermitteln, geht es dann an den eigentlichen Umzug. Zunächst muss verhindert werden, dass der alte Auftritt weiterhin genutzt werden kann. Die .htaccess auf dem alten Server wird daher durch die folgende ersetzt:

RewriteEngine On
RewriteCond %{REQUEST_FILENAME} !.*storedown.*$
RewriteRule .* /storedown.php [L]

storedown.php sollte nicht nur kurz darüber informieren, dass hier gerade ein Umzug im Gange ist, sondern auch einen 503-Header senden, damit auch Google Bescheid weiß:

<?php
header("HTTP/1.1 503 Service Temporarily Unavailable");
header("Status: 503 Service Temporarily Unavailable");
header("Retry-After: 360");
header("Connection: Close");
?>
<!DOCTYPE HTML>
<html lang="en-US">
<head>
	<title>503 Service Temporarily Unavailable</title>
	<meta charset="UTF-8">
</head>
<body>
	<h1>Service Temporarily Unavailable</h1>
	<p>The server is temporarily unable due to maintenance downtime. Please try again later.</p>
</body>
</html>

Der Retry-After-Header sollte einen realistischen Wert in Sekunden enthalten, bis wann der Umzug abgeschlossen sein wird.

Ein letzter Sync zwischen altem und neuen Server stellt sicher, dass auf der neuen Maschine auch der letzte Stand verfügbar sein wird. Der neue Server wird jetzt auf die eigentliche Domain www.domain.de konfiguriert und /etc/hosts auf dem alten Server um folgenden Eintrag ergänzt:

8.8.8.8     www.domain.de

.
Jetzt nur noch die .htaccess auf dem alten Server ersetzen:

RewriteEngine On
RewriteRule ^(.*) http://www.domain.de/$1 [P]

Ohne Zugriff auf die hosts-Datei am alten Server muss mod_proxy angewiesen werden, auf die zuvor eingerichtete Subdomain new.domain.de zuzugreifen:

RewriteEngine On
RewriteRule ^(.*) http://new.domain.de/$1 [P]

Jetzt kann die DNS-Änderung für www.domain.de beantragt werden. Alle Anfragen, die bis dahin noch auf dem alten Server 8.8.4.4 eintreffen, werden mittels mod_proxy und Dank dem Eintrag in der hosts-Datei an den neuen Server weitergereicht – für den Besucher vollkommen transparent.

Umziehen Part 2: 301 mit RedirectPermanent

Weil das gerade so schön durch Abakus durchwabert und ich ja im ersten Teil dieser kleinen Serie strikt davon abgeraten habe, 301-Umleitungen mit RedirectPermanent zu machen, hier noch ein paar ergänzende Worte dazu:

In Teil 1 ging es mir darum, dass schlicht und ergreifend die Domain gewechselt werden, die Inhalte des Auftritts aber brav an der alten Stelle bleiben sollen. RedirectPermanent hilft hier nicht weiter. Der Eintrag in der .htaccess

1
	RedirectPermanent / http://seorockstar.de/

würde wieder auf diesen Auftritt verweisen. Wir würden uns also eine Endlosschleife bauen. Wir brauchen also eine Überprüfung, ob die URL, unter der der Auftritt erreicht wird, überhaupt unterschiedlich zu der ist, zu der wir umleiten wollen. Und das geht schlicht und ergreifend nur mit mod_rewrite und der RewriteCond.

Für was ist dann aber RedirectPermanent überhaupt nützlich?

Beispielsweise dann, wenn man auf eine Domain verweist, die sich mit dieser nicht das physikalische Verzeichnis teilt, man also nicht erst prüfen muss, welche Domain der Besucher aufgerufen hat, bietet sich RedirectPermanent an. Im Vergleich zu mod_rewrite hat eine mod_alias-Lösung nämlich vor allem Performancevorteile, weil nicht erst die RewriteEngine gestartet und Ressourcen zehrend ein regulärer Ausdruck darauf hin überprüft werden muss, ob er zutrifft oder nicht. Auch ist mod_alias in der Lage, den Pfad-Teil der Domain korrekt anzuhängen, der Besucher wird also nicht einfach auf die Startseite geworfen, wenn die Umleitung greift.

Umziehen Part 1: 301

Die Gründe dafür sind vielfältig: Die neue Firmen-CI ist allergisch auf Bindestriche, auch in Domainnamen, man hat sich an der Domain für sein privates Blog sattgesehen oder will mal den großen Subdomain-Aufstand proben. Also registriert man eine neue Domain und zieht den bestehenden Webauftritt dahin um.

Soweit die Theorie. Aber das soll natürlich nicht dazu führen, dass plötzlich alle Links von anderen Seiten oder auch aus den SERPs ins Leere laufen, gleichzeitig soll aber der Auftritt auch nicht unter beiden Domains erreichbar sein – und sei es nur die Startseite, weil moderne CMS- und Blogginglösungen das spätestens ab der zweiten Ebene wieder gerade biegen.

Die Lösung lautet: 301. Wikipedia weiß dazu:

Die angeforderte Ressource steht ab sofort unter der im „Location“-Header-Feld angegebenen Adresse bereit. Die alte Adresse ist nicht länger gültig.

Also genau das, was wir wollen. Immer wieder stolpert man darüber, dass man das mit der Apache-Direktive RedirectPermanent machen soll, aber dazu kann man nur sagen: Finger weg! RedirectPermanent ist Teil von mod_alias und unterstützt daher keine regulären Ausdrücke und keine Bedingungen, wann eine Regel greift und wann nicht. Aber nur damit macht das ganze eigentlich richtig Spaß, wobei bei der Umleitung einer kompletten Domain auf eine andere das ganze auch mit regulären Ausdrücken nicht wirklich kompliziert ist:

1
2
3
4
5
6
<IfModule mod_rewrite.c>
RewriteEngine On
 
RewriteCond %{HTTP_HOST} !^www.notaseo.de$
RewriteRule ^(.*)$ http://www.notaseo.de/$1 [L,R=301]
</IfModule>

Die erste Zeile prüft zunächst, ob mod_rewrite überhaupt verfügbar ist. Was mittlerweile bei so ziemlich jedem Provider der Fall sein dürfte. Die zweite schaltet die Umschreibemaschinerie an. Zeile drei ist eine Bedingung, die prüft, ob der Host, mit dem die Website aufgerufen wurde, nicht www.notaseo.de ist – nur dann greift die nachfolgende Regel, die einfach alles, was nach dem Host kommt, nimmt, in eine Variable $1 schreibt und auf die Zieldomain umleitet. Die Angaben in Klammern sagen aus, dass danach, sollte die Datei weitere Regeln beinhalten, diese nicht mehr abgearbeitet werden (L wie Last) und die Umleitung (R wie Redirect) per 301 erfolgen soll.

Das ganze hat noch einen angenehmen Nebeneffekt: Aufrufe ohne www oder mit irgendwelchen anderen Subdomains leiten immer sauber auf die eigentliche Domain um und man stellt so sicher, dass eine Ressource unter einer kanonischen URL erreichbar ist.

Tut man das ganze aufgrund eines Domainwechsels und nicht, um die Kanonizität sicherzustellen sollte man natürlich anschließend noch versuchen, Backlinks auf die alte Domain durch die Webmaster ändern zu lassen. Schließlich will man die alte Domain auch irgendwann mal kündigen.

Prüfen, ob alles so funktioniert wie gedacht und auch der richtige Statuscode zurückgegeben wird kann man solche Sachen mit diversen Online- und Offlinetools, etwa dem Web-Sniffer oder dem HTTP Client.