Server mieten ist nicht schwer, Admin sein dagegen sehr.

Nach etwas Gemecker, um mal wieder etwas für meinem schlechten Ruf zu tun, zeige ich euch, wie ihr euren Webserver etwas weniger unsicher macht.

Kleine Vorgeschichte

Neulich stolperte ich auf LinkedIn in der Gruppe Artificial Intelligence, Machine Learning, Data Science & Robotics über einen Beitrag mit dem Titel "Hosting a website on AWS EC2 instance using the nginx webserver". Auf 4 Slides/Seiten wurde in 7 einfachen Schritten erklärt, wie man einen Webserver für eine Website mit AWS EC2 einrichtet.

Der Ablauf stellte sich wie folgt dar:

  • 1. starte eine EC2-Instanz
  • 2. verbinde mit der Instanz
  • 3. aktualisiere das System
    • Sudo apt-get update - Ja, das stand da wirklich so!
  • 4. installiere nginx webserver
    • Sudo apt-get install nginx - Ja, auch dieser Befehl stand da so
  • 5. restarte und aktiviere nginx
    • Sudo systemctl restart nginx - no comment...
    • Sudo systemctl enable nginx - ...
  • 6. Upload des Application-Codes
    • Ändere den Application Code in der Datei /var/www/html/index.nginx-debian.html - really, no comment!
  • 7. checke deine Website über die öffentliche IP-Adresse

So weit so gut. Davon abgesehen, dass die meisten Befehle mit einem "command not found" enden dürften, sollte allein schon die Veröffentlichung einer solchen Anleitung als grob fahrlässig betrachtet werden. Wer auf diese Weise einen Webserver für eine öffentlich erreichbare Website einrichtet und betreibt, begeht auf jeden Fall eine grobe Fahrlässigkeit. Leider verleiten gerade solche vermeintlich einfachen Anleitungen unbedarfte User (gern auch aus Management-Ebenen von Unternehmen) dazu, sich nun doch einen eigenen Server zulegen zu wollen, wenn das alles doch so einfach ist. Dass sie damit riskieren, dass ihr Server aufgrund mangelnder Kenntnisse bald die Drohne in einem Botnet wird (evtl. sogar von mehreren), und damit Cyberkriminellen hilft, ihre Angriffe durchzuführen, wird ihnen zumeist erst dann bewusst, wenn Ermittlungsbehörden den Server abschalten lassen oder ein entsprechender Brief ins Haus flattert.

Die Risiken von Cloud-Umgebungen

Doch gerade bei Cloud-Umgebungen, die Infrastructure as a Service (IaaS) bereitstellen, wie Amazon Web Services (AWS), die Azure-Plattform von Microsoft oder Google Cloud Platform (GCP), kommen zu den Risiken, denen ein Server im Internet generell ausgesetzt ist, noch einige finanzielle und rechtliche Risiken für den Betreiber hinzu. Und der Betreiber des Servers ist nicht der Cloud-Anbieter, soviel sei schonmal verraten.

Sind keine passenden Limits für eine solche Server-Instanz gesetzt, und per Default sind sie das zumeist nicht, kann ein Missbrauch oder auch nur ein DoS-Angriff auf eine solche Instanz, der nichtmal in das System eindringen muss, sehr schnell ins Geld gehen. Denn bei solchen Plattformen bezahlt man seine genutzten Services zumeist nach Ressourcen-Verbrauch. Verbraucht man viel Netzwerk-Bandbreite, bezahlt man dafür auch viel. Ohne Monitoring und Deckelung, kann die Summe bis zur nächsten Abrechung durchaus sehr groß werden. Erst vor einigen Wochen musste mal wieder ein unbedarfter AWS-User eine Rechnung von weit über 10.000 Dollar nachzahlen, weil das Gericht den Widerspruch gegen eine durch einen DoS-Angriff entstandene hohe Rechnung abwies.

Doch es braucht nichtmal einen Angriff, um unnötig hohe Kosten zu haben. Wählt man den falschen Typ für seine Instanz aus, hat man schnell mal mehrere hundert Euro Kosten-Unterschied im Monat. Dafür könnte man auch locker einen full-service administrierten Server aus den Händen von Profis bekommen. Man sollte also bereits bei der Auswahl des Instanz-Typs, der letztendlich die verfügbaren Hardware-Ressourcen bestimmt, schon relativ genau wissen, was man braucht. Ist man damit bereits überfordert, wird aus dem vermeintlichen 10-Euro-Hosting für die Website schnell mal ein 300-Euro-Hosting oder mehr.

Und dann wäre da noch die Sache mit dem Datenschutz. Läuft die Instanz innerhalb der EU, oder hat man, vielleicht, um Kosten zu sparen, doch lieber das preiswertere Angebot in den USA genommen? Dann ist ggf. schon die Übertragung der IP-Adressen von Besuchern eine Sache, die dringend vertraglich geregelt werden sollte, handelt es sich dabei doch um personenbezogene Daten, für die der Betreiber des Servers, die verantwortliche verarbeitende Stelle ist. Der Cloud-Provider ist als Auftragsverarbeiter dafür nur begrenzt verantwortlich. Hier greift nämlich das sogenannte "shared responsibility model", das sich je nach Infrastruktur und Anbieter unterscheiden kann.

Ziemlich viel Kauderwelsch für IT-Einsteiger, oder? Wem das bis hierher noch nicht reicht, der folge mir einfach noch etwas weiter auf den dunklen Pfaden eines Sysadmins.

Will man einfach nur eine Website hosten, kommt man mit einen Webspace bei einem der großen Provider in Deutschland ganz sicher kostengünstiger, vor allem aber sicherer, davon. Der Provider kümmert sich dann um die gesamte Infrastruktur und man selbst kann seinen Fokus einfach auf seine Website legen. Denn es ist auch ein Mythos, dass man mit der Cloud IT-Kosten sparen kann. Das mag für einzelne Cloud-Dienste zutreffen, nicht jedoch für IaaS-Plattformen wie AWS, GCP oder Azure. Diese lohnen sich erst dann, wenn man sehr spezielle Anforderungen an seine Webapplikation hat, was bei einfachen Websites ziemlich sicher nicht der Fall ist, solange diese nicht tausende Zugriffe pro Minute verarbeiten müssen.

Doch all das Gemecker und Gelaber, dass man sich keinen Server zulegen sollte - selbst wenn ich auf jedes Risiko, dem ein Server ausgesetzt ist, im Detail eingehen würde - wird erfahrungsgemäß wenig bewirken. Und ich war schließlich auch mal jung... Auch ich wollte unbedingt meinen eigenen Server. Die synchrone echte High-Speed-Anbindung mit statischer IP und eigener Domain waren einfach zu verlockend. Selbst wenn ich kein ganz blutiger Anfänger mit Linux war, machte ich natürlich auch viele Fehler. Manche davon erkannte ich erst viel zu spät. Und bis heute bin ich dem Universum dankbar, dass meine Fehler keinen größeren Schaden anrichteten.

Daher erzähle ich euch lieber, was man tun sollte, um möglichst lange Freude an seinem eigenen Webserver zu haben.

Die Auswahl des richtigen Servers

Schon bei der Auswahl sollte man einiges beachten. Regel Nr. 1 für den ersten eigenen Server: Nutze keine Cloud-Umgebung! Egal ob AWS, Google oder Microsoft, kein IaaS-Anbieter ist für Anfänger geeignet. Denn zusätzlich zu seinem Server muss man ggf. auch seinen (Master-)Account überwachen, damit mit diesem nicht irgendwelche Ressourcen erstellt werden, für die man letztendlich zahlen muss, die jedoch oft hinter wichtige Produkt-Namen verborgen sind und manchmal unsichtbar mitstarten. IaaS-Umgebungen verbergen häufig Komplexität hinter vermeintlich einfachen Web-Interfaces.

Rootserver / Dedicated Server

Lassen wir den Blick also auf andere Angebote schweifen. Da wären bspw. noch die dedizierten Server, auch gern in Fachkreisen als Rootserver bezeichnet, weil man auf diesen volle Root-Rechte hat. Während in meinen Anfangszeiten Single-Core-Maschinen mit knapp 1 GHz und 512 MB RAM für ähnliche Preise wie heute angeboten wurden, ist die Leistung heutiger Rootserver enorm. Für das Hosting eines einfachen Webservers sind sie bei weitem überdimensioniert. Ein moderner Rootserver zum Betrieb einer einzelnen Website, die keine High-Traffic-Seite ist, wäre nur unnötige Strom- und Geldverschwendung. Braucht man jedoch tatsächlich etwas mehr Power oder ist darauf angewiesen, dass verfügbaren Ressourcen voll ausgenutzt werden können, sind sie das Mittel der Wahl. Dann jedoch auch mit den entsprechenden Nachteilen. Ist die Hardware mal defekt, muss diese entsprechend ausgetauscht werden. Im schlimmsten Fall wird auch mal der gesamte Server ausgetauscht und man muss alles aus seinen Backups wiederherstellen. Da sie aber monatliche Festpreise haben, und das über Jahre hinweg, sind ihre Kosten gut planbar und verglichen mit der Leistung vergleichsweise gering (z.B. im Vergleich zu ähnlichen Cloud-Servern).

vServer / virtuelle Server

Ich habe mich vor einiger Zeit von Rootservern weitestgehend verabschiedet und nutze die weitaus preiswerteren, für Privatuser-Bedarf oder kleine Unternehmen jedoch zumeist völlig ausreichenden, sogenannten vServer. vServer sind virtuelle Maschinen (VM). Mit VMs ist es möglich, mehrere Systeme parallel auf einem einzelnen Server (dem sogenannten Host) laufen zu lassen. Dadurch erreichen die Betreiber von Rechenzentren eine besser Auslastung ihrer Hardware. Ein Nachteil dabei ist, dass die Überlastung einer VM auf einem Host-System, auch die Performance von anderen vServern auf dem gleichen Host beeinträchtigen kann. Viele Anbieter bieten daher dedizierte Ressourcen für CPU und RAM, leider jedoch wenige für den Storage-Durchsatz. Durch geschickte Management-Layer kann so eine VM auch problemlos mal auf einen anderen Server geschoben werden, wenn z.B. Updates für das Host-System oder ein Hardware-Tausch anstehen. Als Nutzer merkt man oft nichtmal, wenn der eigene vServer auf eine andere Maschine geschoben wird. Die Verfügbarkeit guter vServer ist dementsprechend hoch. Das beste an vServern ist jedoch, dass man sie für relativ kleines Geld bekommt, man sie in verschiedenen Größen auswählen kann und bei Bedarf kann man bei den meisten Anbietern auch später noch RAM, Plattenplatz oder CPU-Kerne hinzufügen und so den Server mit den eigenen Anforderungen mitwachsen lassen. vServer eignen sich also als günstige Einstiegsserver mit einem gut planbaren Budget.

Auswahl des Anbieters

Nun ist also noch die Frage nach dem Anbieter. Der wichtigste Merksatz dazu: Glaube niemandem, wie toll sein Anbieter ist. Du wirst auch immer Leute finden, die den gleichen Anbieter total schrecklich finden und schlechte Erfahrungen mit ihm gemacht haben. Ich bin z.B. seit meinem ersten Server, zumindest bei meinen privaten Servern in Deutschland, schon immer zu großen Teilen bei Strato. Die schlechten Erfahrungen mit dem Kundendienst, lange Ausfallzeiten und diverse andere Kritik zu diesem Anbieter kann ich oft nicht nachvollziehen. Dafür hab ich mit Hetzner, von dem viele Linux-Sysadmins geradezu schwärmen, weniger gute Erfahrungen gemacht. Mach also einfach deine eigenen Erfahrungen.

Achte bei der Auswahl deines Anbieters aber nicht nur auf die Hardware-Ausstattung des Servers und den Preis. Billige Anbieter mögen zwar die gleichen Hardware-Garantien wie teurere anbieten, oft werden jedoch Zusatzleistungen wie z.B. tägliche Backups, die Möglichkeit ein Rettungssystem zu starten, mit dem man ein kaputtes System wieder reparieren kann oder auch einfach nur eine Domain für den Server nur als zahlungspflichtige Extras angeboten. Bei teureren Anbietern ist es jedoch zum Teil inklusive, wodurch sich Preisunterschiede dann oft auch schnell wieder aufheben können.

Um datenschutzrechtlichen Querelen aus dem Weg zu gehen, sollten vor allem Unternehmen sich für einen Provider aus Deutschland entscheiden, der auch seine Rechenzentren in Deutschland hat. Damit unterliegen sie automatisch der gleichen Datenschutz-Gesetzgebung wie das Unternehmen. Außerdem sollte man darauf achten, dass die verwendeten Rechenzentren mindestens eine Zertifizierung nach ISO 27001 oder vergleichbares haben. Vor allem die Datenverarbeitung bei US-Anbietern kann, je nach verarbeiteten Daten, einiges an zusätzlicher Bürokratie mit sich bringen (Stichwort: Datenschutzfolgeabschätzung).

Auswahl und Setup des Betriebssystems

Ist der Anbieter gefunden und der Server gemietet, geht es nun an das Setup. Viele Anbieter bieten ein System mit einer Administrator-Oberfläche via Webinterface an, die man auch noch auf seinem Server mitsamt den ganzen zuhörigen Komponenten vollautomatisch voreinrichten lassen kann. Zumeist wird das mit cPanel oder vergleichbaren Tools umgesetzt. Mein Rat dazu: Finger weg von webbasierten Administrator-Oberflächen! Auch wenn man mit ihnen erstmal alle möglichen Server-Funktionalitäten quasi auf Klick zur Verfügung hat, stellen Sie ohne zusätzliche Schutzmechanismen oft ein zusätzliches Risiko dar. Außerdem starten sie oft viele Services, die man gar nicht benötigt, wodurch weitere unnötige Angriffsvektoren entstehen. Da auch ihre Eingriffe in die Konfigurationen des Systems eher intransparent sind, gibt es mit ihnen spätestens dann Probleme, wenn man mal eine Einstellung benötigt, die nicht im Webinterface angeboten wird. Und außerdem ist es eh viel cooler, wenn man, wie die richtigen Hacker, sein Linux mittels Kommandozeile administrieren kann. 😉

Viele Anbieter von Miet-Servern stellen verschiedene Systeme für die Vorinstallation von Servern zur Verfügung. Neben verschiedenen Linux-Distributionen gehören dazu, je nach Anbieter, auch verschiedene BSD-Derivate oder auch Windows-Server. Letzteres schlägt jedoch zumeist mit ein paar zusätzlichen Euro Lizenzgebühren pro Monat zu Buche. Generell ist jedoch Linux für einen Webserver eine ziemlich gute Wahl. Ist halt nur die Frage, welches von den vielen.

Zumeist wird Einsteigern zu Ubuntu Linux geraten. Es ist sehr gut dokumentiert und hat eine große Community, in der man um Rat fragen kann, wenn man mal Probleme hat oder bei einer Admin-Aufgabe nicht weiter kommt. Als Ubuntu-User der frühen Stunden (damals konnte man sich noch kostenlose Installations-CDs schicken lassen), würde ich davon auch nicht unbedingt abraten. Ich selbst bevorzuge jedoch Debian GNU/Linux, da es bei Versionswechseln stabiler ist. Beide Distributionen werden bei den meisten Anbietern für die Vorinstallation der Server angeboten. Es sollte jedoch darauf geachtet werden, dass man immer die Minimal-Installation als Basis-System auswählt, die bei fast allen Hostern lediglich aus dem Grundsystem und einem SSH-Server besteht, mit dem man sich auf seinem Server einloggen kann. Andere Distributionen kommen sicher auch in Frage. Ich werde aber hier erstmal auf Debian-Server eingehen. Ubuntu-Server sind ähnlich, nur dass dort kein direkter Root-Login verwendet wird sondern Befehlen, die man mit Administrator-Rechten ausführen will, einfach ein sudo vorangestellt wird.

Die ersten Sicherheitsmaßnahmen - SSH

Hat man sich nun endlich erfolgreich via SSH das erste Mal auf seinem neuen Server mit frisch installiertem Grundsystem eingeloggt, sollten auch schon die ersten Sicherheitsmaßnahmen durchgeführt werden.

Auf Debian-Servern loggt man sich beim ersten Mal oft mit root, also dem Superuser, ein. Mit root sollte jedoch nur auf dem Server gearbeitet werden, wenn man tatsächlich Administrator-Aufgaben erledigt. Damit wir nicht das vom Provider vorausgewählte oder ggf. in sein Setup-Interface eingegebene Passwort weiterverwenden, wird mit dem Befehl passwd ein neues Passwort festgelegt. Bitte beachte, dass ein Superuser-Passwort auf einem Server 15 Stellen oder mehr haben sollte und aus einer möglichst zufällig angeordneten Kombination aus Groß- und Kleinbuchstaben, Zahlen und Sonderzeichen bestehen muss. Passwörter sollten generell in einem Passwort-Manager gespeichert werden, so dass man sie möglichst komplex gestalten kann, ohne sie sich merken zu müssen. Beachte weiterhin, dass Passwörter unter Linux zumeist blind eingegeben werden. Die Eingabe zeigt dir also nicht an, dass etwas eingegeben wurde, wenn du lokal nach einem Passwort gefragt wirst. Tippe also sowohl dein altes als auch dein neues Passwort einfach ein, wenn danach gefragt wird, und bestätige jede Eingabe mit Enter.

Als nächstes brauchen wir einen unprivilegierten "normalen" Nutzer, mit dem wir uns künftig auf dem System einloggen können. Dieser kann mit dem Befehl adduser <benutzername> angelegt werden. Ist der Befehl noch nicht vorhanden, wird er kurzerhand nachinstalliert: apt-get update && apt-get install adduser Hier kombinieren wir 2 Befehle miteinander, wobei das doppelte &-Zeichen zwischen den Befehlen bedeutet, dass der zweite Befehl nur ausgeführt wird, wenn der erste "erfolgreich war", d.h. ohne Fehler durchgelaufen ist. Der erste Befehl aktualisiert den Paket-Index des Paketmanagers 'apt'. Der zweite installiert das Software-Paket, in dem der gewünschte Befehl enthalten ist. Nun können wir also den neuen User anlegen. Bei der Frage, ob eine neue Gruppe für den User angelegt werden soll, antworte mit 'ja'. Der Rest sollte sich von selbst erklären und kann auf Default-Werten gelassen werden. Wir werden den User später noch nach Bedarf anpassen. Auch hier bei der Passwort-Eingabe daran denken, dass Passwörter blind getippt werden. Mittels su - benutzername können wir nun testen, ob der User korrekt funktioniert. Es sollte sich nun eine Shell mit dem neuen Benutzer öffnen, was zumeist am sich verändernden Prompt der Eingabe zu erkennen ist. Man kann seinen aktuellen Benutzer auch mittels whoami aus dem Paket coreutils anzeigen lassen. Ein paar mehr Infos erhält man mit dem Befehl id.

Hat man sich bei seinem ersten Login mittels SSH-Keyfile authentifizieren müssen, was manche Provider mittlerweile zum Schutz vor Bruteforce-Angriffe per Default vorschreiben, muss für den User ein neuer SSH-Key erstellt werden. Wechsle also mit 'su - benutzername' in eine Shell dieses Benutzers. Führe dann den Befehl ssh-keygen aus, mit dem ein neues RSA-Schlüsselpaar für den Benutzer generiert wird. Behalte die Default-Einstellungen durchaus bei. Auch wenn ein Login nur mit Keyfile und ganz ohne Passwort um einiges bequemer ist, solltest du auch deinem SSH-Key ein Passwort verpassen, damit er bei Diebstahl nicht so einfach missbraucht werden kann. Wenn du die Default-Einstellungen von ssh-keygen belassen hast, liegt nun dein neuer öffentlicher Schlüssel in deinem Home-Verzeichnis in der Datei: /home/benutzername/.ssh/id_rsa.pub Diesen kopierst du nach /home/benutzername/.ssh/authorized_keys. Existiert diese Datei noch nicht, lege sie entsprechend an. Den Inhalt der Datei /home/benutzername/.ssh/id_rsa kopierst du auf deinen lokalen Rechner und speicherst ihn in einer Datei, die nur für deinen Benutzer, nicht jedoch für die Gruppe oder andere Nutzer des Rechners lesbar ist. Dies ist dein Private-Key, mit dem du die Verbindung zum Server für diesen Benutzer aufbaust. Lösche die Version auf dem Server, sobald ein Test-Login erfolgreich war.

Hinweis: Windows-Nutzer, die Putty für die SSH-Verbindung zum Server verwenden, müssen den Schlüssel ggf. noch in das richtige Format (ppk - Putty Private Key) umwandeln. Entsprechende Anleitungen findet man zuhauf via Google.

Funktioniert der neue Benutzer, logge dich mit deinem Root-Login aus und verbinde dich neu, diesmal jedoch unter Verwendung des neuen Benutzers und seines SSH-Keys. Der einzige Service, den der Server bisher nach außen bietet, ist SSH. Und damit haben wir natürlich auch den ersten Angriffspunkt. Denn wer es schafft, darüber eine Verbindung aufzubauen, hat Zugriff auf eine Shell auf dem Server. Damit das nur die Leute schaffen, die das auch dürfen, sollte man ein paar Konfigurationseinstellungen überprüfen. Da wir also noch ein paar Einstellungen am System zu machen haben, wechseln wir erstmal zum Benutzer root. Dies erreicht man mit der Eingabe des Befehls su ohne irgendwelche Parameter. Es wird ein Passwort abgefragt, bei dem man das root-Passwort eingibt. Damit sollte man jetzt wieder root-Rechte haben, um die SSH-Server-Konfiguration anzupassen.

Man öffnet die Datei /etc/ssh/sshd_config mit einem Text-Editor. Terminal-Einsteiger nutzen gern den Editor nano. Alte Hasen schwören entweder auf ViM oder Emacs. nano bietet den Vorteil, dass er sehr schnell ist, und am unteren Rand seine Tastenkürzel anzeigt, wobei bei denen ^ für die Steuerungstaste (STRG / control) und M- für die Alt-Taste steht. Zumeist braucht man nur Strg+O zum Speichern und Strg+X zum Beenden. Öffne also die SSH-Server-Konfiguration mit nano /etc/ssh/sshd_config. In der sshd_config sucht man nach der Zeile, die mit PasswordAuthentication beginnt. Stelle sicher, dass dahinter ein 'no' steht. Damit wird die Verwendung eines Passworts für den SSH-Login generell deaktivert. Ein Login ist dann nur noch mittels der SSH-Keys der Nutzer möglich (oder ggf. über ein Rettungssystem, das einige Anbieter bereitstellen). Pass also gut auf deine Keys auf! Suche nun noch nach der Zeile, die mit PermitRootLogin beginnt. Auch diese wird auf 'no' gestellt. Damit kann sich root nicht mehr direkt via SSH einloggen. Für den Login muss ein unauthorisierte "normaler" Nutzer verwendet werden, der sich dann mittels su root-Rechte nach Bedarf verschaffen kann. Wenn du übrigens deine Logins etwas beschleunigen willst, stelle sicher, dass auch der Wert für UseDNS auf 'no' gestellt ist. Jetzt nich die sshd_config speichern und den SSH-Server neustarten... und hoffen, dass kein Tippfehler in die Config geraten ist: systemctl restart sshd

Um das Basis-Setup abzuschließen, sollte das System noch mit allen aktuellen Updates versorgt werden. Ein abschließender Reboot ist zu empfehlen um etwaige Kernel-Updates u.ä. neu zu laden. Anders als bei den Slides bei LinkedIn, nutzen wir allerdings dafür ein richtiges Update, und aktualisieren nicht nur den Paket-Index von 'apt'. 😉 Da wir letzteres vorhin bereits getan haben, können wir diesen Schritt diesmal überspringen. Das Update starten wir mit einem: apt-get dist-upgrade Es wird die Liste der zu aktualisierenden Pakete angezeigt, die mittels 'y', gefolgt von Enter, bestätigt wird. Achte auch darauf, ob Pakete zurückgehalten (not upgraded) werden. Diese muss man ggf. im Nachhinein nochmal mit einem apt-get install paketname aus ihrem Lock-Status herausholen. Handelt es sich jedoch um ein Kernel-Paket, sollte man mit seinem Provider abklären, ob dies für die Hardware des Servers evtl. zwingend erforderlich ist. In dem Fall sollte man es einfach in Ruhe lassen. Der Provider wird sich drum kümmern.

Nach System-Update und Reboot loggen wir uns also wieder ein und haben nun erstmal eine grundlegend saubere Basis, mit der wir arbeiten können. Meckerköpfe werden natürlich sagen, dass dies mit Ubuntu und AWS viel einfacher wäre. Ja, das wäre es, weil Ubuntu per Default keinen root-Login verwendet und weil AWS per Default mit SSH-Keys arbeitet, was nicht alle Server-Anbieter in ihre Default-Images ihrer Distros eingebaut haben. Bei manchen sind die vorinstallierten Systeme auch entsprechend vorkonfiguriert, so dass es bei ihnen entsprechend weniger Schritte bedarf. Ich habe die notwendigen Schritte, ausgehend von einer Debian-Standard-Installation, dennoch hier erklärt, damit man weiß, worauf man achten sollte. Letztendlich sollte ein SSH-Login mit dem Benutzer root oder mittels Passwort-Authentifizierung nicht mehr möglich sein. Remote-Logins solllten ausschließlich mit Non-Admin-Benutzern durchgeführt werden.

Will man, wie unter Ubuntu üblich, lieber mit sudo-Befehlen arbeiten, kann man das natürlich auch einrichten. Dazu installiert man das Paket 'sudo' und passt die Konfiguration in /etc/sudoers nach eigenen Wünschen an. Üblich ist es, eine spezielle sudoers-Gruppe anzulegen, die entsprechende Rechte mit Hilfe der sudoers-Datei eingeräumt bekommt. Alle Benutzer, die in dieser Gruppe sind, können dann Befehle mittels sudo als root ausführen. Man sollte jedoch sicherstellen, dass sie trotzdem noch ihr eigenes Benutzerpasswort eingeben müssen, um den sudo-Befehl zu autorisieren. sudo ohne Passwort ist zwar schön bequem, sollte auf Servern aber vermieden werden.

Noch immer läuft kein Webserver, und doch haben wir schon einiges am System verändert, um es Angreifern zu erschweren, Benutzeraccounts via SSH zu knacken. Können wir jetzt also endlich den Webserver einrichten?

Endlich... der Webserver

Nginx ist für viele Anwendungsfälle ein echt guter Webserver. Deswegen wird er auch mittlerweile fast schon als Quasi-Standard verwendet. Als ich mit der Administration von Webservern anfing, gab es Nginx noch nicht und fast alle setzten auf den Apache HTTPd, auch bekannt als Apache Webserver. Seine lange Entwicklungszeit hat ihn natürlich sehr robust gemacht, aber in einigen Anwendungsbereichen auch etwas träge. Bleiben wir also erstmal bei Nginx, um mit einem halbwegs modernen Tech-Stack zu starten.

Die Installation erfolgt, wie zu erwarten, durch die Installation des zugehörigen Pakets: apt-get install nginx Wie alle Installationen, muss auch diese mit root-Rechten durchgeführt werden. Die Default-Konfiguration, die bei der Installation eingerichtet wird, findet man in /etc/nginx/ schön verteilt auf viele "übersichtliche" Dateien. Startet man diese Default-Konfiguration, lierfert der Server die Datei /var/www/html/index.nginx-debian.html auf allen IP-Adressen des Servers via HTTP auf Port 80 aus. Damit kann man z.B. prüfen, ob netzwerkseitig alles passt und die Firewall auch passend eingestellt ist.

Aber man will ja seine eigene Homepage bauen. Soll der Webserver auch zukünftig nur eine Website ausliefern, maximal noch die gleiche Seite unter mehreren Domains, kann man dieses Verzeichnis für seine Homepage problemlos beibehalten. Ansonsten empfiehlt es sich, unter /var/www/ oder /home/www/ für jede Seite ein eigenes Unterverzeichnis anzulegen. Man kann aber z.B. unter /home/ auch einfach einen extra Ordner für das neue Website-Verzeichnis anlegen. Für diese Anleitung bleiben wir dabei und liefern die Website aus dem Verzeichnis /var/www/html aus. Doch bevor wir dazu kommen, wie man seine eigene Index-Datei als Website ausliefert, sollten wir einen Blick in die globalen Einstellungen des Nginx werfen. Es sollte bspw. sichergestellt werden, dass in der Datei /etc/nginx/nginx.conf, die den Ausgangspunkt zum Laden aller anderen Dateien der Konfiguration darstellt, der Server etwas weniger "gesprächig" gemacht wird. Hierfür müssen innerhalb der http-Direktive die Server-Tokens ausgeschaltet werden: server_tokens off; Nun verrät unser Server nicht mehr jedem Scanner, welche Version von Nginx er gerade nutzt. Angreifer nutzen Versionsnummern in Server-Tokens, um gezielt Systeme mit fehlenden Updates und bekannten Sicherheitslücken zu identifizieren.

Als nächstes sollte geprüft werden, welche Erweiterungsmodule der Server ggf. zusätzlich lädt und welche man ggf. deaktivieren kann, weil man sie nicht braucht. Ein Blick in den Ordner /etc/nginx/modules-enabled/ offenbart normalerweise einige Links, die auf Dateien im Ordner /usr/share/nginx/modules-available/ verweisen. Am Dateinamen kann man oft die Funktion ableiten. Ansonsten findet sich über Google aber auch ausreichend Doku zu den Modulen. Lösche alle Links zu Erweiterungen in /etc/nginx/modules-enabled/, die du nicht benötigst.

Generell sollten Server-Systeme so schlank wie möglich gehalten werden. Jede in einem Server geladene Erweiterung kann irgendwann mal eine Sicherheitslücke aufweisen. Je weniger Erweiterungen also aktiv sind, umso geringer ist die Wahrscheinlichkeit, dass eine Erweiterung mit einer potentiellen zukünftigen Sicherheitslücke geladen ist.

Das Website-Verzeichnis vorbereiten

Die Konfiguration für die Website, die der Server ausliefert, findet sich in der Datei /etc/nginx/sites-enabled/default. Auch hierbei handelt es sich wieder um einen Link, der auf die Datei /etc/nginx/sites-available/default zeigt. Dadurch kann man Websites einfach deaktivieren, indem man den Link entfernt. Die eigentliche Konfiguration bleibt aber erhalten, um sie bspw. später wieder zu verwenden. In dieser Konfiguration findet wir erstmal nur einen server-Block, in dem eine sehr grundlegende Konfiguration enthalten ist. Entfernt man alle Zeilen, die mit einem #-Zeichen beginnen, da es sich dabei nur um Kommentare handelt, die grundlegende Konfigurationen erläutern, dürfte etwa Folgendes übrig bleiben.

server {
  listen 80 default_server;
  listen [::]:80 default_server;

  root /var/www/html;

  index index.html index.htm index.nginx-debian.html;

  server_name _;

  location / {
    try_files $uri $uri/ =404;
  }

  location ~ /\.ht {
    deny all;
  }
}
          
Wie an dem Wert für index zu erkennen ist, können wir einfach in /var/www/html eine Datei mit dem Namen index.html ablegen, um damit unsere eigene Index-Datei auszuliefern. Sie würde gegenüber der index.nginx-debian.html bevorzugt werden. Um Ordnung zu halten und keine unnötigen Dateien rumliegen zu lassen, löscht man die /var/www/html/index.nginx-debian.html jedoch besser und entfernt sie aus der Liste möglicher Index-Dateien.

Außerdem ist es ratsam, ein paar Ressourcen-Limits für jede Website einzustellen, um DoS-Angriffe zu erschweren. Sofern die genutzte Webanwendung keine speziellen Anforderungen an ihre Ressourcen im Webserver hat, sollten die Werte für client_body_buffer_size, client_header_buffer_size, client_max_body_size sowie large_client_header_buffers so klein wie möglich gehalten werden. Fange mit den in der Tabelle aufgeführten Werten an und erhöhe sie nur, wenn sie Probleme mit deiner Website verursachen.

DirektiveEmpf. Wert
client_body_buffer_size1k
client_header_buffer_size1k
client_max_body_size1k
large_client_header_buffers2 1k

Solltest du Datei-Uploads mittels POST-Requests durchführen, muss der Wert für client_max_body_size entsprechend vergrößert werden, um die gewünschte Upload-Größe zuzulassen. Aufgrund dieser Abhängigkeit sollte man bessere Upload-Möglichkeiten in seiner Webapp nutzen, wenn man sie schon unbedingt anbieten muss. In jedem Fall sollte ein Antiviren-Scan für Uploads von Webapps durchgeführt werden. Daß Linux sicher gegen Malware ist, ist ein weit verbreiteter Mythos, aber leider nunmal ein Mythos. Auch wenn Viren auf Linux nicht so verbreitet sind, wie auf anderen Systemen, gibt es jedoch gerade im Server-Umfeld jede Menge Malware, wie z.B. Rootkits, Kernel-Trojaner oder Bots. Jede Ransomware-Crew hat seinen Crypter auch als Linux-Version im Gepäck. Und häufig werden Server mit Bots infiziert, die diese für Crypto-Mining missbrauchen.

Um auch die Angriffspunkte via HTTP möglichst klein zu halten, sollten die vom Nginx zugelassenen HTTP-Methoden auf ein notwendiges Minimum reduziert werden. Für eine normale Website reichen die HTTP-Methoden GET, HEAD und POST zumeist aus. Der Rest kann mittels limit_except im Konfigurationsblock location / deaktiviert werden. Füge dazu folgende Zeile ein:
limit_except GET HEAD POST { deny all; }

Zur Verhinderung von Clickjacking-Angriffen solltest du das Laden der Seite in iFrames unterbinden, indem du die X-Frame-Options für jede Antwort des Servers festlegst:
add_header X-Frame-Options "SAMEORIGIN";

SSL-Verschlüsselung für Website-Besucher

Bevor wir uns noch weiteren Konfigurationsanpassungen, die der Sicherheit dienen, zuwenden, müssen wir kurz die Konfiguration von SSL anschauen, also der Möglichkeit, eine Website über HTTPS anstelle von HTTP aufzurufen, damit die Verbindung verschlüsselt wird. Da die meisten Suchmaschinen Websites ohne HTTPS mittlerweile abstrafen und dank Projekten wie Let's Encrypt, die kostenlose SSL-Zerifikate erstellen und die zur Validierung notwendige Infrastruktur bereitstellen, kann jeder Betreiber eines Servers mittlerweile SSL-Verschlüsselungen für seine Websites umsetzen. Die Zertifikate des Projekts werden in der Regel von allen gängigen Browsern akzeptiert. Im Netz finden sich jede Menge Anleitungen, wie man das Tool certbot installiert und verwendet, um SSL-Zertifikate für Domains, die auf den jeweiligen Server zeigen, zu erstellen. Da eine Wiederholung dessen an dieser Stelle etwas zu weit führen würde, gehe ich mal davon aus, dass in /etc/letsencrypt/live/domain.tld/ die notwendigen Dateien erstellt wurden, so dass sie im Nginx verwendet werden können. Wobei domain.tld natürlich der Domainname ist, für den man sein Zertifikat erstellt hat. Der certbot-Aufruf dafür könnte etwa so ausgehen haben: certbot certonly --webroot -w /var/www/html -d domain.tld -d \*.domain.tld Damit bekommt man auch gleich ein sogenanntes Wildcard-Zertifikat für alle Subdomains wie z.B. www.domain.tld.

Für den HTTPS-Zugriff muss eine weitere Sektion server zur Datei /etc/nginx/sites-available/default hinzugefügt werden. Diese sollte grundlegend den folgenden Inhalt haben:

server {
  listen 443 ssl;
  server_name domain.tld www.domain.tld;
  root /var/www/html;
  index index.html index.htm;

  
  ssl_ecdh_curve              secp384r1;
  ssl_protocols               TLSv1.2 TLSv1.3;
  ssl_ciphers                 HIGH:!aNULL:!MD5:!ADH:!eNULL:!LOW:!EXP;
  ssl_prefer_server_ciphers   on;
  ssl_session_timeout         10m;
  ssl_session_cache           shared:SSL:10m;
  ssl_session_tickets         off;
  ssl_stapling                on;
  ssl_stapling_verify         on;
  ssl_dhparam                 /etc/nginx/dhparams.pem;

  ssl_certificate             /etc/letsencrypt/live/domain.tld/fullchain.pem;
  ssl_certificate_key         /etc/letsencrypt/live/domain.tld/privkey.pem;

  add_header Strict-Transport-Security    "max-age=31536000; includeSubDomains" always;
  add_header X-Content-Type-Options       nosniff;
  add_header Content-Security-Policy      "default-src 'self' http: https: data: blob: 'unsafe-inline'" always;
  add_header X-XSS-Protection             "1; mode=block";
  add_header X-Frame-Options              "SAMEORIGIN";

  location / {
    client_body_buffer_size     1k;
    client_header_buffer_size   1k;
    client_max_body_size        1k;
    large_client_header_buffers 2 1k;
    limit_except GET HEAD POST { deny all; }
    try_files $uri $uri/ =404;
  }
  location ~ /\.ht {
    deny all;
  }
}
          

Die hier genutzte Datei dhparams.pem kann mit diesem Befehl erstellt werden: openssl dhparam -out /etc/nginx/dhparams.pem 4096

Will man, dass alle Website-Besucher, die die Seite über HTTP aufrufen, automatisch zur verschlüsselten Verbindung umgeleitet werden, kann man hierfür einfach eine Umleitung legen, indem man für die Domain ein neues HTTP-Host anlegt:

server {
  listen                80;
  server_name           domain.tld www.domain.tld;
  return 301            https://$host$request_uri;
}
          

Wir haben also nun 3 Server-Konfigurationen: eine für alle Anfragen, die auf einer Domain eintreffen, die der Server nicht kennt (sowie Direktzugriffe auf seine IP-Adresse), eine für HTTPS-Anfragen für die Domains domain.tld und www.domain.tld sowie eines, dass die HTTP-Anfragen für domain.tld und www.domain.tld nach HTTPS umleitet. Wird nun langsam klar, warum die Anleitung auf LinkedIn nicht funktionieren konnte, selbst wenn die Befehle richtig geschrieben gewesen wären?

Doch werfen wir noch kurz einen Blick auf unser SSL-Vhost ("Vhost" ist eine gängige Abkürzung für virtuelle Hosts auf einem Server). Die listen-Direktive verweist nun natürlich auf Port 443 für HTTPS und erwartet dort einen Verbindungsaufbau mit SSL-Verschlüsselung. Der Block mit den ssl_-Direktiven legt logischerweise die Konfiguration für SSL fest. Hier sind für Administratoren vor allem die Direktiven ssl_protocols und ssl_ciphers wichtig. Sie legen fest, welche TLS-Versionen der Server von anfragenden Browsern akzeptiert und welche Verschlüsselungsalgorithmen zugelassen werden. Die aufgezeigte Konfiguration deaktiviert die meisten schwachen und veralteten Algorithmen. Der SSL-Test von SSL Labs dürfte mit dieser Konfiguration ein recht gutes Ergebnis liefern.

Neben möglichst optimalen Einstellungen für die SSL-Verschlüsselung werden auch noch zusätzliche HTTP-Header gesetzt, um STS festzulegen und einen grundlegenden XSS-Schutz zu ermöglichen.

Was denn nun noch?

Erst jetzt ist der Server grundlegend eingerichtet. Weitere Anpassungen und Optimierungen können je nach Auslastung und Bedrohungslage vorgenommen werden. Doch auch wenn das Setup jetzt getan ist, ist die Arbeit am Server damit nicht beendet. Es muss regelmäßig überprüft werden, ob neue Updates bereitstehen. Kritische Sicherheitsupdates sollte man bei Servern überlicherweise binnen 24h einspielen. Doch auch weniger kritische sollten nicht unbedingt monatelang herausgezögert werden. In Verbindung mit einer weiteren vielleicht entdeckten Lücke, kann durchaus schnell mal eine größere Lücke daraus werden.

Durch ihre statischen IP-Adressen und aufgrund ihrer Natur, Dienste im Internet öffentlich anzubieten, sind Server unter ständigem Beschuss. Man spricht nicht umsonst von einem "Internet-Hintergrundrauschen". Server werden ständig von Bots gescannt, und auf veraltete Software mit bekannten Schwachstellen überprüft. Manchmal feuern solche Bots auch einfach nur blind ihre Exploits auf IP-Adressen, in der Hoffnung, dass eines davon funktioniert. Erfahrungsgemäß ist es nur eine Frage der Zeit, bis selbst solche Bots ihre nächsten Opfer finden. Hinzu kommt ein wachsender Markt der Cyberkriminalität, der schon längst eine sauber strukturierte organisierte Cyberkriminalität bildet.

Cyberkriminalität ist ein Milliarden-Markt. Wenn du einen Server betreibst, der 24/7 mit immer der gleichen IP online ist, solltest du dir bewusst sein, dass er schon aufgrund seiner Ressourcen, wie z.B. einer synchronen Breitband-Anbindung, ein interessantes Ziel ist, um ihn als Bot-Host in ein Botnet aufzunehmen. Nachlässigkeit in der Pflege eines Servers können manchmal gutgehen, tun es erfahrungsgemäß aber dauerhaft nicht. Vor allem Leute, die nur sehr grundlegende Linux-Kenntnisse haben, aber dennoch eigene Server betreiben wollen, merken häufig gar nicht, wenn ihr Server bereits Teil eines Botnets wurde. Sofern der Server nicht gerade einen Cryptominer-Bot bedient, der sich zumeist schnell an der hohen Systemlast und der damit schlechten Server-Performance erkennen lässt, kann der Server auch erstmal als schlafende Drohne Teil eines Botnets sein, bis der Botnet-Eigentümer eine Aufgabe für ihn hat, wie z.B. den Versand von Spam, das Weiterreichen illegaler Daten-Kopien aus Ransomware-Angriffen oder die Unterstützung bei einem DDoS-Angriff. Möglichkeiten, solche Bots zu monetarisieren, gibt es viele. Die meisten davon sind jedoch in Deutschland verboten.

Deswegen sollte man als Betreiber seines Servers diesen auch überwachen. Dazu gehört, dass man sowohl seine Erreichbarkeit von einer externen Quelle aus überwacht, als auch seine System-Ressourcen im Blick behält. Auffälligkeiten z.B. bei Auslastungsspitzen, Benutzer-Aktivitäten, Login-Versuchen oder Netzwerk-Sockets sollte man sich immer genauer anschauen und bei Bedarf entsprechende Gegenmaßnahmen ergreifen. Die Nutzung eines HIDS wie OSSEC kann dabei helfen, ungewöhnliche Aktivitäten im System schneller aufzuspüren. Ich lasse mir z.B. Logins auf meinen Servern in einen Slack-Channel schreiben, so dass ich zeitnah sehe, wenn User-Logins plötzlich von ungewöhnlichen IP-Adressen oder zu ungewöhnlichen Zeiten auftauchen. Doch keine Sorge, auch ohne 24/7-Monitoring kann so ein Server relativ sicher betrieben werden. Dann muss man halt extra viel Wert auf einen aktuellen Update-Stand aller Software und eine besonders sichere Konfiguration legen.

Abschließende Anmerkungen

Selbst diese lange Erklärung sollte nicht darüber hinwegtäuschen, dass hier bei weitem nicht alle Hardening-Maßnahmen beschrieben sind, die auf einem Linux-Webserver möglich oder ratsam sind. Vom noexec-Flag für Temp-Ordner oder RBAC mit SELinux über die Isolierung von Server-Prozessen mit Containern oder die richtigen Kernel-Settings bis hin zur Nutzung von EDR/XDR sind die meisten möglichen Security-Maßnahmen hier noch gar nicht zur Sprache gekommen. Das wäre nämlich für einen einfachen Homepage-Eintrag einfach zu viel. Allein zur Konfiguration von Nginx kann man ganze Bücher kaufen. Ich hoffe jedoch, dass ausreichend aufgezeigt wurde, dass Server verwalten nichts ist, was der Rudi aus der 10. Klasse mal so eben kann, nur weil der Linux benutzt und die Anleitung bei LinkedIn total einfach aussieht. Dieser Text ist nicht als vollumfängliche Anleitung für die Einrichtung eines sicheren Webservers gedacht. Er kann höchstens ein paar Denkanstöße geben, welche weiteren Schutzmaßnahmen der eigene Server wert ist und was man ggf. noch alles lernen sollte, bevor man einen Server im Internet betreibt.

Doch jeder fängt natürlich klein an. Man sollte nur aufpassen, dass man auf dem Weg zum erfahrenen Sysadmin, nicht aus Versehen so stark hinfällt, dass man nicht mehr aufstehen kann.

Und übrigens... vergiß nicht regelmäßig Backups von den geänderten Konfigurationen, deinen SSL-Zertifikaten, den Home-Verzeichnissen der User, dem Website-Ordner usw. zu machen. Man sollte immer ein Backup außerhalb des Providers haben, bei dem der Server läuft. Generiere dir dafür auch gleich noch eine Liste der installierten Software-Pakete, damit du deinen Server zur Not auch einfach umziehen kannst.