Docker mit NGINX-Proxymanager, UFW, Fail2Ban, MariaDB und Nextcloud — Teil 2

Nicht benötigte Container, Volumes & Images löschen

Willkommen zum zweiten Teil meiner Docker-Serie.

Bitte lest unbedingt auch die vorhergehenden Teile!Nachdem wir unsere Dockerinstallation mittels des  „hello-world-Container“ nur getestet haben, ist nun ein für uns nun nutzloser Container vorhanden. Deshalb löschen wir selbigen. Es ist generell ratsam, nicht verwendete Container, Images, Volumes etc. zu entfernen. Nach dem Löschen des Containers, ist auch das Image von „hello-world“ zu löschen.

Installation NGINX-Proxy Manager

Der NGINX-Proxymanager (kurz NPM) wird anfragen vom externen Netzwerk (Internet) entgegen nehmen und diese dann zum jeweiligen Container weiterleiten. Für jede Weiterleitung muss ein Full-Qualified-Domain-Namen (eine Domäne, Subdomäne…) vorhanden sein.

D.h. beispielsweise, dass die Subdomain portainer.it-networker.at an Container „portainer“ bzw. dessen Container-IP weitergeleitet wird.

Ebenso wäre es möglich eine Subdomain proxy.it-networker.at zu erstellen und diese dann vie NPM an unseren NPM-Container weiterleiten zu lassen.

Widmen wir uns aber zuerst der Einrichtung.

Volumes erstellen

Wir benötigen 2 sogenannte Volumes. Ein Volume verweist auf das Dateisystem des Servers (Hosts). Selbst nach einem Neustart, oder der Neuerstellung des betroffenen Containers, bleiben die Daten auf diesem quasi „gemappten“ Dateisystem erhalten.

Es sind 2 Volumes zu erstellen:

  • Ein Datenverzeichnis für den NPM
  • Ein Datenverzeichnis für Letsencrypt (SSL Zertifikate)

Anmerkung: Der NPM macht es möglich, durch Einbindung von Let’s encrypt, kostenlose offizielle SSL Zertifikate zu erstellen.

In Portainer wählen wir links Volumes, dann oben rechts „Add Volume“ und vergeben (ganz oben) als Name „nginx_data“. Es ist völlig egal, welchen Namen ihr hier vergebt. Wichtig ist nur, dass ihr das Volume später eindeutig zuordnen könnt. (Ihr müsst wissen, welches Volume ihr hier für welchen Container vorbereitet habt 😉 ).

Alle anderen Einstellungen belassen wir auf den Vorgaben und klicken auf „Create the volume“.

Das Volume für Letsencrypt erstellen wir auf die gleiche Art und Weise. Ich wähle hierfür den Namen „letsencrypt_data“.

Container erstellen

In Portainer klicken wir links im Menü auf „Containers“ und danach oben rechts auf „Add Container“.

  • Der Name kann beliebig vergeben werden. Ich wähle „NginxPM“.
  • Als Image bitte: jc21/nginx-proxy-manager:latest eingeben.
  • Unter „Network ports configuration“ -> Manual network port pubishing auf „publish a new port“ klicken und folgende Ports erstellen. (Für jedes zusätzliche Port immer wieder auf „publish a network port“ klicken.

Sieht dann so aus:

NGINX-PM wird anfragen auf 80 und 443 annehmen. Port 81 ist das Managementport.

Advanced Container Settings

Command and Logging

Interactive & TTY wählen (=man hat dann eine Konsole für den Container, in die man sich einloggen kann).

Volumes

Im Reiter Volumes müssen wir nun unsere erstellten Volumes für den NPM zuordnen. Wir klicken also 2x auf „map additional volume„, da wir ja auch 2 Volumes zuordnen wollen.

Die Zuordnung der Volumes sollte nun so aussehen:

Network

Network wird aktuell noch auf den Standardeinstellungen belassen.

Env & Labels

Hier kann man Umgebungsvariablen (ENVironment variables) für den Container ein-/erstellen. In unserem Fall müssen wir hier aber nichts ändern oder eintragen. Dies gilt ebenso für den Reiter Labels.

Restart policy

Hier wird es wieder interessant, denn mit dieser Policy kann gesteuert werden, wie sich der Container z.B. nach einem Hostneustart verhält. Wir setzen die Policy auf „Always“.

Runtime & Resources / Capabilities

Können so belassen werden. Die Standardeinstellungen sind in dem Fall ok.

Container „deployen“

Nun ist es an der Zeit den Container auszurollen und zu starten. Dies gelingt mit einem simplen Klick auf „Deploy the container„. Läuft alles glatt, wird nun das Image heruntergeladen und der Container mit unseren Einstellungen gestartet. Landet ihr nach dem Deployment auf folgender Seite, dann hat alles wie gewünscht funktioniert.

Erreichbarkeit prüfen

An sich müsste der NGINX-PM nun auf Port 81 ansprechbar sein. Der Versuch eines Aufrufs von http://portainer.it-networker.at:81/ führt jedoch zu einem Fehler. Die Website ist nicht erreichbar.

Nach kurzer Überlegung wird klar, weshalb das so ist. Wir hatten ja im ersten Teil via ufw-Firewall den Zugriff auf Port 22 und 9443 eingeschränkt. Ein anderer Port ist ja eingehend nicht offen. Hat man eine öffentliche statische IP, kann man den Zugriff auf Port 81 des Containers (NGINX-PM) freigeben:

ufw route allow from <eure öffentliche IP> to 172.17.0.3 port 81

Jetzt klappts…

Danach könnt ihr euch bei eurem NGINX-PM einloggen. Der Standarduser ist admin@example.com, das Passwort changeme

Nach dem Login, müsst ihr eure „Admindetails“ angeben und ein neues Passwort setzen.

UFW Firewall anpassen & IP-Adresse des NGINX-PM adaptieren

Alle eingehenden Anfragen auf Port 80 oder 443 sollen ausschließlich auf den NGNIX-PM weitergeleitet werden. Es ist klar, dass unsere UFW –  Firewall angepasst werden muss. Hier kommt es jetzt aber zu einem kleinen Problem, denn Docker vergibt innerhalb des Standardnetzwerkes (172.17.0.x) die IP Adressen automatisch (DHCP). Es könnte theoretisch passieren, dass die Container bei jedem Neustart eine andere IP-Adresse bekommen.

Unsere Firwallregeln wären somit dann im schlimmsten Fall nutzlos bzw. würden zumindest ins Leere laufen.

Ein eigenes Netzwerk erstellen

Um dem entgegen zu wirken, erstellen wir uns ein eigenes Netzwerk.

  • In Portainer wählen wir auf der linken Seite „Networks“ und folgend oben rechts „Add Network“.
  • Der Name kann frei vergeben werden.
  • Driver verbleibt auf „bridge“.
  • Unter „IPV4 Network configuration“ müssen wir nun aber eine IP Adresse vergeben. Ich wähle hier „10.0.0.0/24“. Hiermit stehen uns also 254 Adressen zur Verfügung.
  • Ebenso müssen wir einen Gateway eintragen. (10.0.0.1)

Abschießend einfach noch ganz unten auf „Create the network“ klicken.

Wir haben nun also ein „eigenes Netzwerk“ mit dem Adressraum 10.0.0.1-10.0.0.254 erstellt. Aufgrund dessen können nun Container erstellt werden, die eine fixe IP bekommen. Diese IP-Adresse bleibt auch erhalten, wenn der Container neu gestartet wird.

NGINX-PM IP Anpassungen

Wir wollen, dass der NGINX-PM immer die IP Adresse 10.0.0.3 erhält. Der Container muss also angepasst werden. In Portainer wählen wir links „Containers„, danach suchen wir uns in der Liste rechts den NPM heraus, klicken ihn an und klicken oben auf „Duplicate / Edit„.

Bei den nun angezeigten Einstellungen, nach unten scrollen, bis zu „Advanced container settings“ und wählen den Reiter „Network“ aus.

Im Dropdown „Network“ wählen wir das zuvor erstellte Netzwerk bei mir „it-networker„. Weiter unten bei „IPV4 Address“ ist nun die gewünschte IP – bei mir 10.0.0.3 – einzugeben.

Letztlich „deployen“ wir den Container nochmals per Klick auf „Deploy the containter„. Die Nachfrage „Are you sure?“ quittieren wir mit „Replace„.

Unser NPM hat nun die IP 10.0.0.3

Achtung: Ufw-Firwall

Nachdem sich die IP unseres NGINX-PM geändert hat, muss nun ufw wieder angepasst werden!

Mittels ufw status numbered lassen wir uns die geltenden Regeln anzeigen.

Die „alte Regel“ -unten Nr 3- für den NPM (NGINX Proxymanager) kann gelöscht werden.

ufw delete 3

…und entsprechend bestätigen.

Um  weiterhin Zugriff auf den NPM zu haben, muss eine neue Regel erstellt werden:

ufw route allow from <eure öffentliche IP> to 10.0.0.3 port 81

Jetzt ist der NPM wieder für euch erreichbar! (Port 81)

Dies sollte nur eine kurzfristige Lösung sein! Vor  allem dann, wenn ihr keine statische öffentliche IP habt. Spätestens, sobald der NPM via Subdomain und HTTPS erreichbar ist, ist die oben angeführte Firewallregel zu löschen, denn die Verbindung ist nicht verschlüsselt!

Eigene Subdomain für NPM

Das, was wir oben bezüglich des Netzwerkes durchexerziert haben, war einerseits nötig, diente aber auch Verständnis. Es ist jetzt an der Zeit, den NPM über eine Subdomain anzusprechen. Natürlich via SSL!

Ich habe deshalb eine neue Subdomain im DNS meines Providers angelegt. Diese lautet proxy.it-networker.at

Zusätzliche Regeln mit ufw erstellen

Jeder soll von extern auf Port 80 und 443 unseres NGINX-PM Container (der intern auf IP 10.0.0.3 läuft) zugreifen können. Die Aktion ist auch nötig, damit wir uns via Letsencrypt ein valides SSL Zertifikat für die Subdomain proxy.it-yourself.at holen können!

 ufw route allow from any proto tcp to 10.0.0.3 port 80

ufw route allow from any proto tcp to 10.0.0.3 port 443

Die  weitere Einrichtung erfolgt nun im Adminbackend des NPM (Port 81/http mit dem FQDN)

  1. Einloggen in den NPM
  2. Auswahl des Reiters SSL Certificates
  3. Klick (oben rechts) auf Add SSL Certificates -> Letsencrypt
  4. Bei „Domain Names“ tragt ihr bitte eure Subdomain ein, die ihr für den NPM vorgesehen habt. Achtung wenn ihr den FQDN im Feld eingegeben habt, nicht Return drücken, sondern gleich unterhalb auf „Add <euer FQDN>“ klicken.
  5. Unten „I Agree……….“ wählen
  6. Auf Save klicken

Der Test „Test Server Reachability“ ist nicht immer erfolgreich. Ich führe ihn deshalb nicht jedesmal durch. Egal, ob der Test erfolgreich ist, oder nicht. Nach dem Klick auf Save, dauert es meist rund 30 – 40 Sekunden und ihr habt euer Zertifikat.

Regel im NPM für proxy.it-networker.at erstellen

  • Oben klick auf Hosts -> Proxyhosts
  • Mittig (grüner Button) -> Add Proxy Host
  • Domain Names: proxy.it-networker.at (nach Eingabe wieder auf das Add… unten klicken)
  • Scheme: http
  • Forward Hostname / IP: Name des Containers: NginxPM / oder IP
  • Forward Port: 81
  • Block common exploits
  • Reiter SSL: Das zuvor erstellte SSL Zertifikat auswählen
  • Force SSL
  • HTTP/2 Support
  • Save

Gebt ihr nun https://<eure Subdomain> ein -> in meinem Fall https://proxy.it-networker.at gelangt ihr HTTPS-Verschlüsselt direkt zum Login euers NPM.

Zugriffssteuerung / Absicherung

Es ist jetzt an der Zeit, die Firewallregel, die einen direkten Zugriff auf Port 81 (des NPM) erlaubt, zu löschen. Mittlerweile wisst ihr schon, wie das geht.

ufw status numbered

Danach die betreffende Regel sichten und per Nummer davor in der Eckigen klammer löschen.

ufw delete 2

Natürlich kann es sein, dass die betroffene Regel bei euch eine andere Nummer hat!

Weiter zu Teil 3

Diskussionsforum zum Thema

Docker mit NGINX-Proxymanager, UFW, Fail2Ban, MariaDB und Nextcloud — Teil 1

Willkommen zum ersten Teil meiner Docker-Serie. Ich versuche in diesem mehrteiligen Tutorial darzustellen, wie man Docker auf einem VServer verwenden kann. Wenn ihr so etwas vor habt, müsst ihr euch dessen bewusst sein, dass dieser Server 24/7 im Internet steht. Der Server muss also laufend aktualisiert und auch überwacht werden. Dies gilt für den Host selbst, aber natürlich auch für die Dockercontainer! Wo immer möglich, solltet ihr Zugriffe einschränken, auf IPtables (ufw) zurückgreifen und ein Monitoring und Update-tool installieren.

 💡 WICHTIG: Das hier ist KEINE Docker-Rootless-Installation! D.h. die Prozesse innerhalb der Dockercontainer laufen mit dem User root. Selbst wenn man Container mit einem Standarduser ausrollt, heißt es nicht, dass somit alle anderen Prozesse (der Container) „rootless“ laufen.

Ich habe den Zugriff auf die Dienste, die vom Internet aus zugreifbar sind, auf meine 2 statischen öffentlichen IPs eingeschränkt. Sofern ihr aus Sicherheitsgründen Docker ohne Root verwenden wollt, gibt es hier eine ganz gute Anleitung (allerdings auf englischer Sprache). Ich werde mich dem Thema später zuwenden, jedoch nicht innerhalb dieser Artikelserie.

Zielsetzung

  • Auf einem Server, der im Internet steht, oder aus dem Internet erreichbar ist, wird -basierend auf Ubuntu Server – Docker installiert.
  • Es ist bereits ein Full-Qualified-Domain-Name (eine Domain) registriert, die auf den Dockerhost zeigt. In meinem Fall ist das portainer.it-networker.at
  • Als Verwaltungstool kommt Portainer zum Einsatz.
  • Zum Schutz von Host und Client wird UFW eingesetzt.
  • Nachdem die gesamte Netzwerkkonnektivität von Docker via iptables gesteuert wird, wird UFW adapiert, damit die – mittels UFW- gesetzten Regeln greifen.
    ACHTUNG: Eine nicht-adaptierte Konfiguration von UFW hat zur Folge, dass -sofern man Containerports „exposed“ = nach außen öffnet- jeder von überall aus  darauf Zugriff hat! (Mehr dazu unten in der Anleitung)
  • Es wird NGINX-Proxy-Manager installiert, der die Verbindungen von außen zu den angebotenen Webseiten / Services „verwaltet“.
  • Über den NGINX-Proxy-Manager werden via Letsencrypt SSL Zertifikate zur Verfügung gestellt.
  • Fail2Ban (im Dockercontainer) sorgt für die zusätzliche Absicherung von Host und Container.

Weiterlesen