Die Sache mit den virtuellen DocumentRoots

Posted by jonas on Wednesday, December 6, 2017

tl;dr

  • Wir hatten uns in der Entwicklung darauf verständigt, virtuelle DocumentRoots - ein Feature von U5 und U6 - bei U7 nicht mehr als Feature anzubieten, sondern im Lauf der U7-Beta ein neues Dashboard zu releasen, mit dem es viel einfacher sein wird, mehrere Uberspaces zu verwalten, so wie wir uns das als “best practice” vorstellt haben. (Der Plan mit dem neuen Dashboard besteht natürlich weiter, und die Arbeit daran hat auch schon begonnen.)
  • Wir haben schon damit gerechnet, dass diese Entscheidung erläuterungsbedürftig werden könnte. Der Widerspruch etlicher User traf uns allerdings in größerem Umfang, mit stärkerer Enttäuschung und mit Argumenten, die wir zu bedenken hatten. Wir wollten keinen “Okay, okay, okay”-Schnellschuss machen und unsere Entscheidung einfach wieder umwerfen, aber wir haben uns mit Usern ausgetauscht und Argumente und Use Cases eingesammelt, darüber gesprochen, und am Ende haben wir beschlossen, die virtuellen DocumentRoots entgegen der ursprünglichen Planung auch auf U7 einzuführen.
  • Nach wie vor raten wir deutlich davon ab, dieses Feature zum Hosting mehrerer unterschiedlicher Projekte in einem Account zu verwenden, weil zwischen jenen Projekten dann keine Rechtetrennung besteht. Wenn Rechtetrennung wichtig ist - und das ist sie im Zweifelsfall fast immer - solltest du wie bisher dem Rat folgen, mehrere Uberspaces anzulegen. Wir werden das vereinfachen, versprochen.

Worum geht’s eigentlich?

Vom Konzept her ist ein Uberspace dazu gedacht, ein Projekt darauf zu hosten. Dafür wird /var/www/virtual/<user>/html als DocumentRoot angeboten. Schon ziemlich in der Anfangszeit trafen Fragen bei uns ein, ob man da nicht die Möglichkeit schaffen könnten, für kleinere Sachen einfach separate Verzeichnisse anzulegen, um keinen separaten Uberspace dafür anzulegen - “das lohnt doch gar nicht”. Wir waren mit Uberspace gerade erst gestartet, voller Tatendrang, ein wenig blauäugig vielleicht auch, und dachten uns: Klar, basteln wir doch schnell eine RewriteRule, und schon war das Feature geboren: User konnten ab sofort in /var/www/virtual/<user> einfach weitere Verzeichnisse ablegen, die so hießen wie Hostnamen, und schon wurden Anfragen nach jenen Hostnamen aus diesem Verzeichnis bedient (vorausgesetzt, der Hostname wurde auf den Uberspace aufgeschaltet). So weit, so gut - oder besser gesagt: So weit, so okay.

Probleme, Probleme

Im Support schlagen - bis heute - immer wieder die gleichen Probleme auf:

  • Wer innerhalb eines virtuellen DocumentRoots mit RewriteRules arbeiten möchte, benötigt RewriteBase / - das ist einfach so, und wir haben keinen Weg gefunden, das zu vermeiden. Wir weisen bereits deutlich in der Dokumentation darauf hin und vermeiden damit sicherlich eine Reihe von Anfragen, aber aus bleiben sie dennoch nicht.
  • Die Umgebungsvariable DOCUMENT_ROOT, die der Apache-Webserver für Applikationen bereitstellt, beinhaltet prinzipiell den echten DocumentRoot, also den Pfad des html-Verzeichnisses, nicht den virtuellen DocumentRoot. Häufig ist das irrelevant; wenn allerdings User oder Applikationen diese Variablen aus Ausgangswert für irgendwelche selbst-konstruierten Pfade verwenden, fällt einem das auf die Füße.
  • User haben des Öfteren solche virtuellen DocumentRoots angelegt und sich dann - bis hin zu einer Supportanfrage - gewundert, warum sie nicht funktionieren, obwohl sie einfach nur vergessen haben, jenen Hostnamen auch in die Konfiguration des Webservers eintragen zu lassen. Umgekehrt haben manche verzweifelt Dateien in ihrem html-Verzeichnis geändert und sich gewundert, warum sich die Änderungen nicht im Web widerspiegelten, bis wir sie darauf hingewiesen haben, dass sie für den verwendeten Hostnamen offenbar früher mal irgendwann einen virtuellen DocumentRoot angelegt hatten und dann vergessen hatten, dass er da ist.

Das alles sind natürlich vergleichsweise leicht erklär- und lösbare Schwierigkeiten - Schwierigkeiten, die mit dem echten DocumentRoot html aber eben nicht auftreten.

Tragisch wird es aber dann, wenn es um Einbrüche mittels Lücken in von Usern installierter Software geht. Lückenhafte WordPress-Themes oder veraltete Joomla- und Drupal-Installationen bilden da in der Praxis so das Grusel-Trio. Und hier ist dann das Problem: Derartige Einbrüche streuen typischerweise Backdoors überall hin, wo der Angreifer Schreibrechte hat. Und das heißt beim Einsatz von virtuellen DocumentRoots: Wenn ich da ein halbes Dutzend Dinge in einen Account stopfe (ein CMS, ein Blog, einen Merch-Shop, einen persönlichen RSS-Reader, ein Ticketsystem und noch eine Applikation, die ich irgendwann mal ausprobiert und dann vergessen habe), dann sind eben alle diese Applikationen den Sicherheitslücken aller dieser Applikationen ausgesetzt - eine einzelne Lücke reicht aus, und schon sind Backdoors auch in den Verzeichnissen von Applikationen installiert, die gar keine bekannten Lücken beinhalten.

Natürlich können wir dann sagen: Naja, darauf haben wir dich doch deutlich hingewiesen. Aber es ist ja nicht sonderlich zielführend, einem User, dem wir gerade schon die Gesamtheit seiner DocumentRoots wegen eines Einbruchs sperren mussten, noch ein “selber schuld” an den Kopf zu knallen, egal wie freundlich und konstruktiv man das formuliert.

Außerdem versuchen wir, in die nicht ganz so nahe Zukunft zu blicken, denn nachdem sich herauskristallisiert hat, dass Uberspace wohl keine Eintagsfliege wird, sondern sich sogar ziemlich gut und zu unserem Haupt-Umsatzträger entwickelt, haben wir natürlich auch gewisse Ideen und Pläne, wo wir gerne hin wollen. Das heißt auch, dass wir zwischen maximaler Flexibilität und guter Usability gelegentlich auch mal einen Tradeoff machen müssen und - da machen wir uns nichts vor - nicht mit jeder Entscheidung alle User immer glücklich machen können, auch wenn wir natürlich darum bemüht sind, das möglichst gut hinzukriegen. Das fordert aber eben auch Nachdenken und Zeit. Bei U5/U6 haben wir viele Dinge mehr oder weniger auf Zuruf realisiert - teils mit positiven Effekten; teils auch mit Folgen, wo wir uns im Nachhinein gewünscht hätten, vielleicht lieber vorher etwas mehr nachgedacht zu haben, weil wir uns in Situationen gebracht haben, die später nicht mehr zu revidieren waren. Dass wir U7 von Grund auf neu bauen, beinhaltet auch, dass wir jedes einzelne Feature nochmal ans Reißbrett bringen und uns fragen, wie sich das auswirken kann - vom nackten Feature abgesehen also auch zu fragen: Was für Support wird das generieren, und wieviel? Wie stabil wird das sein? Welche Fehler in der Handhabung oder im Betrieb können wir antizipieren? Sehen wir möglicherweise Kompatibilitätsprobleme mit anderen Komponenten von U7? Da kann man hier und da sehr wohl zu dem Schluss kommen, dass man etwas schon bei U5/U6 praktisch optimal gebaut hat; manches hingegen wird ganz anders als früher gebaut, selbst wenn es sich aus Usersicht sogar ähnlich oder identisch benutzen lässt.

Zu jenen Abwägungen zwischen Flexibilität und Usability gehört beispielsweise die bisher nur ganz lose Idee, sich vielleicht später einmal mit Ansible-Playbooks zu beschäftigen, die beliebte Applikationen auf einem Uberspace installieren. Ihr wisst schon: So ein Pendant zu One-Click-Installern, aber eben in nachvollziehbar, weil man ja in die zugrundeliegenden Playbooks eben reinschauen kann, um zu sehen, was konkret da passieren wird, und die man ggf. auch forken und abwandeln kann, wenn man nicht einverstanden ist - und das eben auf der Basis eines verbreiteten Open-Source-Tools und nicht auf einer selbst gebauten proprietären Lösung. Dafür ist aber eben stärker als bisher Voraussetzung, dass ein definierter Zustand vorgefunden wird, und dafür erschien uns sinnvoll, festzulegen, dass solche Playbooks ihre Dinge eben immer in den einen, offiziellen DocumentRoot installieren sollten und alles andere die Dinge arg verkomplizieren würde.

Also war die - aus unserer Sicht - naheliegende Idee geboren: Wir lassen das mit den virtuellen DocumentRoots fortan einfach bleiben. Statt zu empfehlen, separate Uberspaces anzulegen, forcieren wir künftig, dies zu tun. Das erspart uns nebenbei den oben genannten Support - was natürlich zwei Aspekte hat: Einerseits ist es natürlich ohne Frage gut für uns, wenn der Support entlastet wird, damit er mehr Zeit für andere Fragen hat; andererseits ist es für die User Experience natürlich auch besser, wenn ein User gar nicht erst über ein Problem fällt, statt erst darüber zu fallen und dann erstmal Hilfe suchen zu müssen. Den Plan, das Anlegen mehrerer Uberspaces über ein neues Dashboard signifikant zu vereinfachen, hatten wir ohnehin schon lange - und er passte gut dazu.

Vielleicht war das ein wenig ungeschickt

Nun ist es natürlich so: Das neue Dashboard gibt es noch nicht, auch wenn die Arbeit daran inzwischen begonnen wurde. Es erscheint natürlich irgendwie unklug, erst das fragliche Feature der virtuellen DocumentRoots als bei U7 abgeschafft zu erklären, und erst dann irgendwann später ein neues Dashboard vorzustellen, was dazu in der Lage ist, das zu kompensieren, aber wir hatten uns das wie folgt gedacht:

  • Wir haben ja nun nicht das bestehende Feature bei U5/U6 entfernt (das stand überhaupt nie zur Debatte), sondern es lediglich bei einer künftigen Produktversion weggelassen.
  • Wir sind bei U7 ohnehin schon viel, viel, viel zu lange von Release early, release often abgewichen und hatten einen dicken Knoten zu durchschlagen, was wir nicht durch Abhängigkeiten á la “Das können wir erst tun, wenn jenes Feature in jenem anderen Produktteil - dem Dashboard - fertig ist” noch weiter hinauszögern wollten.
  • Es erschien uns schlüssig, zu argumentieren: Wenn du virtuelle DocumentRoots brauchst, kannst du ja einfach noch bei U6 bleiben, denn da gibt es sie ja. U7 ist erst eine Beta, und wir werden zwar nicht dort das Feature einbauen, aber parallel dazu im Dashboard entwickeln, so dass du ihm, sobald du dort eine viel einfachere Verwaltung mehrerer Uberspaces hast, gar nicht nachzutrauern brauchst.

Also haben wir’s gemacht, wie wir es eben gemacht haben, und das war… vielleicht ein wenig ungeschickt.

Argumente, Argumente

Uns war wichtig, dass wir jetzt nicht einfach so sagen: Ohje, die User sind unzufrieden, also bringen wir’s hektisch wieder. Wir hatten uns ja immerhin etwas dabei gedacht, das Feature nicht mit aufzunehmen - aber der Druck war schon spürbar. Also hat Matthias sich drangesetzt und hat die Punkte, die User so vorgebracht haben, gesammelt und strukturiert:

  • Es könnte sein, dass mehrere Projekte in einem Uberspace auf denselben Datenbestand zugreifen - beispielsweise ein Staging-System.
  • Nur, weil wir keine virtuellen DocumentRoots mehr anbieten, verhindern wir ja nicht, dass User sich nicht dennoch einen Haufen Applikationen in einen einzigen Uberspace packen, also eben CMS, Blog, Shop, … nur dann eben nicht in Form von Subdomains, sondern das müsste dann in Unterverzeichnissen laufen. Den gewünschten forcierten Sicherheitsgewinn hätten wir damit dann nicht erzielt.
  • Gleiches gilt z.B. für die Installation mehrerer Dienste auf mehreren Ports, kombiniert mit einer .htaccess-Datei mit RewriteRules, die Requests anhand unterschiedlicher %{HTTP_HOST}-Werte an unterschiedliche Ports schicken.
  • Derzeit ist eben die Verwaltung mehrerer Uberspaces noch nicht wirklich gegeben, außer rudimentär via OpenID. Ein neues Dashboard wird das lösen.
  • Insbesondere für ein gemeinsames Aufladen gibt es noch keine wirklich runde Lösung. Das wird sich ändern, insofern ist das perspektivisch eher kein Problem mehr, aber im Moment eben schon noch.
  • Einige User empfinden es als Einschränkung, dann nicht mehr “mal eben schnell” etwas testen zu können. Unser Argument wäre hier, dass gerade zum Testen ein ganz neu angelegter Uberspace, der anschließend entsorgt werden kann, doch eigentlich die besonders gute Lösung wäre, vor allem, weil man damit dann keine Produktivdaten einem Risiko aussetzt; allerdings wenden User auch ein, dass solche Tests auch mal länger als den kostenlosen Testmonat dauern können und nicht automatisch weggeräumt werden sollen (wogegen wir wiederum einwenden können, dass es riskant ist, Tests lange liegenzulassen - im Zweifelsfall wird einem dann ein Jahr später über eine zwischenzeitlich entdeckte Sicherheitslücke in der testweise installierten Applikation dann der Account aufgemacht; leider auch eine Praxis-Erfahrung). Aber diese Argumente kann man trefflich Ping-Pong spielen lassen.
  • User verwenden virtuelle DocumentRoots zum Teil für Mikro-Projekte (nennen wir sie mal “Web-Visitenkarte”), teils mit rein statischen Inhalten, bei denen Rechtetrennung kein Thema ist, weil dort ohnehin keine dynamischen Inhalte ausgeführt werden.
  • Insbesondere für solche kleinen Mikro-Projekte erscheint einigen Usern selbst der symbolische Mindestpreis von 1 Euro als zu hoch. Teils ließ sich aus Äußerungen direkt oder indirekt herauslesen, wir seien jetzt wohl “geldgeil” geworden, weil das Anlegen von 10 Uberspaces für 10 Mikro-Projekte dann eben halt auch nicht mehr für ’nen Fünfer oder gar weniger im Monat zu haben sei.
  • Auch ein Datenschutz-Aspekt wurde genannt, den wir so tatsächlich gar nicht auf dem Schirm hatten: Wenn unter <user>.uber.space und unter domain.tld forciert die gleichen Inhalte abrufbar sind, kann man regelmäßig aus einem Usernamen auf einen Domainnamen schließen. (Wobei sich das immer noch via .htaccess hätte verhindern lassen, aber wir haben gelernt, dass es User gibt, die für den internen Hostnamen einfach einen separaten, leeren DocumentRoot angelegt haben und jenen somit abgeklemmt haben.)
  • Etwas weg vom technischen Bereich gingen dann Äußerungen, dass sich User die Meinung, wie denn mit mehreren Projekten umgegangen werden möge, nicht von uns “vorkauen” lassen möchten. Teils fiel auch der Begriff “Elfenbeinturm”.

Zurück ans Reißbrett

Unsere teaminternen Gespräche dazu waren hart, und wir können offen zugeben, dass mehrere von uns im Verlauf dieser Gespräche ihre Meinung geändert haben; in unterschiedliche Richtungen; teils sogar mehr als einmal. Worin wir uns aber sehr schnell einig waren: Wenn User beginnen, den Eindruck zu äußern, wir säßen in einem Elfenbeinturm, dann machen wir etwas nicht richtig, oder zumindest kommunizieren wir etwas nicht richtig. Sehr wahrscheinlich aber auch schlicht und einfach gleich beides.

Wir können ohne Umschweife zugeben: Wir finden nicht alles super, was User bei uns so machen bzw. wie sie es machen - also, aus technischer Sicht. So, jetzt ist es raus. Steinigt uns. (Bitte nicht.)

Allerdings ist Uberspace seit Tag 1 ein Produkt, bei dem wir ein großes Augenmerk darauf gelegt haben, möglichst viel von der Freiheit, die Linux und die Shell so bieten, an User weiterzugeben. Und das hat selbstverständlich zur Folge, dass unterschiedliche User unterschiedliche Problemstellungen auch unterschiedlich angehen und es nicht an uns ist, da zwischen “falsch” und “richtig” zu urteilen. Die - ganz prinzipielle - Herausforderung ist: Wie kriegen wir ein Produkt hin, das für User einfach zu benutzen ist und ihnen aber dennoch möglichst viele Freiheiten lässt?

U5/U6 sind davon charakterisiert, dass wir in erster Linie viele Freiheiten gelassen haben. Das ist allerdings teils mit Ecken und Kanten verbunden, wo wir heute sagen würden: Ohjeohje, da müssen wir aus Usability-Sicht aber nochmal ran, das können wir so nicht shippen. Denn nur weil wir zu einem nicht gerade kleinen Teil Nerd-User haben, die schon lange auf einer Shell Zuhause sind, heißt das ja nicht, dass wir uns nicht darum bemühen sollten, Dinge flexibel, aber eben auch einfach zu machen. Ein Uberspace soll aus unserer Sicht einfach ein gutes Produkt sein und kein Statussymbol á la “Darauf können sich die Leute, die das bedienen können, etwas einbilden”. Deshalb sind wir bestrebt, den Spagat zu schaffen, etwas zu bauen, was für alle leichter zu benutzen ist, aber denen, die tiefer graben wollen, keine Steine in den Weg legt.

Jeder der einen Spagat hinlegen kann, weiss, dass diesem ein langer Lernprozess vorausgeht. Und wir haben daraus gelernt. Für diese Erfahrung - die wir auch bei künftigen Designentscheidungen stets im Kopf behalten werden - können wir jedem Einzelnen, der uns Contra gegeben hat, nur danken.