Spezifische php und Apache Konfiguration und externer Zugriff auf Container

  • Setup

    • QNAP TS 251+
    • Image: Joomla 3.9.1-php7.2-apache
    • Ziel: Aktuelle Joomla Version mit php7.2 und nativer Datenbank auf Host betrieben sowie Mapping von /var/www/html auf Host-Verzeichnis und individueller zusätzlicher Konfiguration von php und Apache mit internem und externem Zugriff

    Problem 1: Kein externer Zugriff

    Ich betreibe die NAS mit internem und externem Zugriff durch Portfreigabe in der FritzBox als Entwicklungsumgebung, der Zugriff erfolgt von außen über QNAPKENNUNG.myqnapcloud.com. Das funktioniert auch hervorragend für alle native Apps (Admin-UI, Filestation, Photostation ect.), aber nicht für den gestarteten Container. Die NAT-Portmappings 8100:80 und 8101:443 sind eingetragen, so dass ich zwar im internen Netzwerk über http://NASNAME:8100 problemlos zugreifen kann, aber wenn ich versuche von außen über http://QNAPKENNUNG.myqnapcloud.com:8100 zuzugreifen, kommt nach Timeout nur eine Fehlermeldung. Mit dem Container ist auch automatischer ein virtueller Switch eingerichtet worden und ich bin davon ausgegangen, dass dieser dafür sorgt, dass auch externe Aufrufe an den laufenden Container weitergegeben werden, aber das scheint nicht der Fall zu sein.

    Fragen:

    • Funktioniert eine externer Zugriff generell mit NAT oder muss ich ein HOST oder BRIDGE Mapping einrichten (und damit auch separate Portweiterleitung)?
    • Wenn ja: Wie muss den Container und/oder ggf. der virtuelle Switch konfiguriert sein, damit externe Zugriff gleich wie interner funktioniert?

    Problem 2: php- und Apach-Konfigurationsdateien ganz oder gar nicht

    So wie ich diverse Tutorial verstanden habe, sollte die im Container laufende php/Apache Umgebung folgendermaßen konfiguriert werden können (am Beispiel php):

    1. PHP startet im Container und liest die im Container vorhandene Standard-php.ini
    2. Die gegebene PHP Konfiguration --with-config-file-scan-dir=/etc/config/php.d veranlasst php im Verzeichnis /etc/config/php.d nach zusätzlichen *.ini Dateien zu suchen
    3. Dort vorhandene gültige INI-EInstellungen überschrieben die Werte der Standard-php.ini

    Ich habe den Container so eingerichtet, dass das Container-Share /usr/local/etc/php/conf.d auf das Host Share /share/php7-apache/config/php/conf.d gemappt wird und dort eine Datei custom.ini enthalten ist, die spezifische Einstellungen enthält. Allerdings funktioniert der oben beschriebene Ablauf nicht, denn sobald ich den Container mit dem Mapping starte, erwartet PHP offenbar, dass alle Konfigurationsdateien darin enthalten sein müssen, also auch die Standard php.ini und alle Erweiterungen, damit sind immer alle Werte aus Local value und Master value identisch. D.h. das selektive Laden bestimmter Einstellungen funktioniert nicht, entweder muss alles aus dem Container kommen (kein Konfig-Mapping zum Host) oder alles wird von außen gelesen (aus bestehendem Konfig-Mapping zum Host), aber selektiv mit z.B. einer einzigen Datei custom.ini, die nur die vom Standard abweichenden Einstellungen enthält klappt nicht.

    Fragen:

    • Wie kann ich erreichen, dass alle notwendigen Standardkonfigurationsdateien (inklusive Erweiterungen) aus dem Container gelesen werden und nur spezifische Einstellungen aus einer custom.ini?


    Vermutlich sind beides wieder super einfache Anfängerprobleme, aber trotz vieler gelesener Tutorials und Dokus ist es mir in 3 Wochen nicht gelungen, das Ganze wie oben beschrieben zum Laufen zu bringen, also ist mir jeder Tipp willkommen.

  • Hallo outsch!


    Ich habe da selbe Problem, ich möchte von außerhalb auf den eingerichteten Container zugreifen können. Beim Herumspielen habe ich mir die komplette Netzwerkkonfiguration verstellt, so lange in der FritzBox für die NAS "Selbstständige Portfreigaben für das Gerät erlauben" aktiviert war, war die NAS über https://QNAPKENNUNG.myqnapcloud.com:8100 in Netz erreichbar, nie aber der Conatiner, dem der Port 3772 zugewiesen war.


    Wär sehr an einer genauen und umfangreichen Erklärung interessiert, sodass ich den Container dementsprechend einrichten kann.


    LG

    Einmal editiert, zuletzt von ph2 ()

  • Hallo Paul,

    schön zu lesen dass es auch Leidensgenossen gibt :)

    Ich habe bei mir aus Sicherheitsgründen die automatische Portweiterleitung ausgeschaltet, und die benötigten Ports manuell geöffnet. Ich werde wohl auch mal probieren, ob HOST anstatt NAS als Netzwerkkonfiguration externen Zugriff auf den Container erlaubt - wenn ich das richtig verstehe müsste dann der Container wie eine eigene physischen Maschine im Netz auftauchen und von der Fritzbox eine separate IP bekommen. Wenn ich damit Erfolg habe werde ich berichten.

    Das ganze Docker Gedöns ist ja super von der Idee her, aber wie ich schon vor der Beschäftigung damit befürchtet habe liegt die Komplexität in den Schnittstellen. Und gerade weil ich gehofft habe mit den QNAP Oberflächen mir die etwas tiefere Kenntnis von Linux ersparen zu können sehe ich jetzt, dass das alles eben doch gelernt werden muss. Gleiches gilt übrigens auch für phpmail - das funktioniert auch nicht in meinem Container. Das kann ich in Joomla zwar auch direkt über SMTP konfigurieren, aber es wäre eben schön wenn das auch aus dem Container ginge, nur ist das wie alle einzelnen Punkte wieder mit stundenlangem googeln und vermutlich wieder dem unleidigen Installieren von Erweiterungen verbunden.

    Ergo: Bis die Docker-Container das machen was man will und sich wie eine native Maschine verhalten ist es halt doch ein langer, zäher und sehr komplizierter Weg!

  • Ich glaube, dass für dein Problem NAT nicht geeignet ist.


    Bei einer Anfrage auf eine Internetseite im öffentlichen Netz wird im TCP-Protokoll als ZIel Port z.B. Port 80 bzw. 443 (für http bzw https) eingetragen und als Quell -Port eine zufällige Nummer vergeben. Der Router merkt sich diese Zufallsnummer in Verbindung mit der privaten IP des anfragenden Hosts aus dem internen Netz. Dann ersetzt (daher der Name NAT) der Router die private IP-Adresse des anfragenden Hosts durch seine öffentliche IP Adresse und adressiert so den externen Webserver (Ports bleiben 80 bzw. 443). So funktioniert der Zugriff nach außen. Die Antwort des Webservers wird dann an die öffentliche IP-Adresse des Routers gesendet mit dem Zufallsport von eben. Anhand dieses Ports kann der Router wieder seine öffentliche IP durch die private IP des Hosts ersetzen.


    Umgedreht geht das dann halt eben nicht mehr. Da ist der Zielport z.B. 80 und der zufällige Quellport gehört nicht in unser Netzwerk. Das geht dann nur mit Portforwarding.




    Im Bridged-Modus kann man z.B. eine feste IP-Adresse vergeben, über diese ist der Container dann erreichbar. Da muss am virtuellen Switch eigentlich nix gemacht werden, du solltest die Adressen halt aus dem gleichen Netz verwenden.

  • Einen Webserver betreibt man wenn in einer DMZ und nicht im gleichen Netz.

    Dazwischen gehört eine Firewall die das System von den lokalen Netzen trennt.

    Denn so ein Webserver wird ständig angegriffen und wenn da eine Lücke drin ist, wird der auch übernommen.


    Mal eben so eine Webseite hosten endet dann oft im Chaos, in dem Fall könnte auch das NAS gleich mit gekapert werden. Deine Daten werden dann unter Umständen verschlüsselt oder landen überall im Internet.


    Ohne Sicherheitskonzept sollte man davon die Finger lassen.


    Dann lieber ein paar € für nen Hoster hinlegen.

    Der Pracht zwar nicht aber er informiert einen über neue Lücken so das man selber aktiv werden kann.


    Ansonsten musst du dich selber informieren und deine ganze Strucktur auf stand halten.

    Ja auch Firewalls bekommen Sicherheitsupdates verpasst.


    Das ist ein Fulltimejob oder ein Mega Risiko.

  • Nach vielen weiteren Stunden habe ich jetzt hinbekommen, was ich wollte: Eine im Docker Container laufende Anwendung, die von außen erreichbar ist und deren Verbindung nicht nur über https abgesichert ist, sondern deren Zertifikat auch von den strengen Browsern als gültig angesehen wird und nicht zur Fehlermeldung Zertifikat NICHT SICHER führt. Außerdem kann ich die Konfiguration des Containers (Joomla 3.9.1+php 7.1 + apache) einfach von außen (d.h. über Windows am PC mit Editor) ändern und dort auch die Log-Files ansehen, ohne jedes Mal mit SSH "zu Fuß" mit die Finger zu brechen.


    So ganz ohne SSH bin ich aber auch nicht ausgekommen, aber es beschränkt sich auf wenige Schritte:

    1. Image ziehen und temporären Container erstellen
      In der Container Station suche ich nach Joomla und wähle in meinem Fall das Tag 3.9.1-php7.2 aus. Der Container wird so konfiguriert, dass er die (bestehende) native Datenbank der NAS nutzt und in einer ersten, temporären Variante die Config-Dateien des Apache zunächst im Container hat - allerdings nur zum Zwecke des Kopierens auf den Host um diese später einfacher im Zugriff haben:
      1. Umgebung:
        JOOMLA_DB_HOST 192.168.xxx.yyy:3306 (wobei xxx.yyy die tatsächlichen IP-Teile darstellen)
        JOOMLA_DB_NAME MeineJoomlaDB
        JOOMLA_DB_USER JoomlaUserName
        JOOMLA_DB_PASSWORD JoomlaPassword
        GID 100
        UID zzzz

        GID und UID sind dabei die Gruppen-ID und die User-ID eines separaten Users, unter dessen Identität der Container betrieben wird.
      2. Netzwerk (Ports)
        9100 80
        9101 443
      3. Freigaben (wobei die hostseitig angegebenen Ordner [hier: "joomla-container" und darunter] angelegt, aber leer bis auf den JoomlaOrdner sind sind leer!):
        /share/joomla-container/apache-log -> /var/log/apache2
        /share/joomla-container/php/custom.d -> /usr/local/etc/php/custom.d
        /share/Web/JoomlaOrdner -> /var/www/html

        Ich vergebe für den Container den Namen joomla-temporary und nach Klick auf Erstellen zieht die NAS das Image vom Dockerhub und erstellt den Container.
    2. SSL Modul aktivieren und Apache-Konfiguration aus dem Container auf den Host kopieren
      1. Mittels SSH (z.B. PuTTY) auf der NAS anmelden
      2. Da das SSL-Modul offenbar noch nicht im Original-Image aktiviert war, gehe ich zunächst in den laufenden Container mit
        docker exec -it joomla-boagle /bin/bash
        und aktiviere dort das bisher fehlende SSL-Modul mit
        a2enmod ssl
      3. Mittels exit verlasse ich den laufenden Container und bin wieder auf der NAS
      4. Ich kopiere nun die gesamte Apache-Konfiguration auf den Host in die zuvor eingerichteten Ordner [hier: "joomla-container" und darunter] mit:
        docker cp -L joomla-temporary:/etc/apache2 /share/appdata/joomla-container
        Der Schalter -L ist wichtig, damit die SYMLINKS mitkopiert werden - so können später Module oder neue Seiten bedarfsweise mit a2enmod aktiviert werden.
        Danach kann ich in der FileStation oder auch im Windows Explorer sehen, dass es nun das Verzeichnis joomla-container/apache2 gibt, das alle Konfigurationsdateien von Apache enthält.
    3. Zertifikat bereitstellen
      Das QNAP-Zertifikat, dass ich eigentlich habe, lässt sich nach Freigabe auch herunterladen, aber es hat sich als untauglich erwiesen. Also gehe ich in Systemsteuerung > Sicherheit > Zertifikat & privater Schlüssel und wähle Zertifikat ersetzen und dann Let'sEncrypt und gebe dort meine Domain meinqnapname.myqnapcloud.com ein, deren Verfügungsberechtigung QNAP ja bestätigen muss. Nach wenigen Augenblicken ist das Zertifikat fertig und kann als ZIP-Datei heruntergeladen werden. Ich packe die drei Dateien aus und speichere sie im dazu erstellten Verzeichnis /share/appdata/joomla-container/apache2/certificates aus, dort stehen dann nach:
      1. SSLcertificate.crt
      2. SSLIntermediateCertificate.crt
      3. SSLprivatekey.key
    4. Finalen Container erstellen
      Ich stoppe den laufenden temporären Container und erstelle auf Basis den nun vorhandenen Images einen neuen, der bis auf eine Änderung gleich konfiguriert wird wie der vorherige temporäre:
      1. Umgebung:
        JOOMLA_DB_HOST 192.168.xxx.yyy:3306 (wobei xxx.yyy die tatsächlichen IP-Teile darstellen)
        JOOMLA_DB_NAME MeineJoomlaDB
        JOOMLA_DB_USER JoomlaUserName
        JOOMLA_DB_PASSWORD JoomlaPassword
        GID 100
        UID zzzz
      2. Netzwerk (Ports)
        9100 80
        9101 443
      3. Freigaben:
        /share/joomla-container/apache2 -> /etc/apache2 Diese Freigabe ist hinzugekommen!
        /share/joomla-container/apache-log -> /var/log/apache2
        /share/joomla-container/php/custom.d -> /usr/local/etc/php/custom.d
        /share/Web/JoomlaOrdner -> /var/www/html
    5. Zertifikat installieren
      Ich prüfe ob den Container läuft und stoppe ihn dann wieder. Dann editiere ich die Datei (in WIndows!)
      /share/joomla-container/apache2/sites-available/000-default.conf
      und ergänze sie um folgenden Eintrag:
      <VirtualHost *:443>ServerAdmin meine-mail@adresse.comDocumentRoot /var/www/htmlServerName meinqnapname.myqnapcloud.comSSLEngine onSSLCertificateFile /etc/apache2/certificates/SSLcertificate.crtSSLCertificateKeyFile /etc/apache2/certificates/SSLprivatekey.keySSLCertificateChainFile /etc/apache2/certificates/SSLIntermediateCertificate.crt</VirtualHost>
      Ggf. ergänze ich Servername und e-mail im oberen *:80 Abschnitt ebenfalls und speichere sie.
    6. Container neu starten
      Ich starte den Container neu in der Containerstation und kann sowohl auf
      http://meinqnapname.myqnapcloud.com:9100
      als auch auf
      https://meinqnapname.myqnapcloud.com:9101
      zugreifen und bekomme keiner Zertifikatsfehler mehr angezeigt, d.h. die Anwendung läuft von außen (WIndow) konfigurierbar und mit von außen einsehbaren Logfiles und mit gültigem Zertifikat!:)

    Übrigens an Crazyhorse: Erstens ist das immer noch ein Entwicklungsprojekt und wird später selbstverständlich bei einem Hoster gehostet, Aber während der Entwicklung ist es eben viel bequemer, alles lokal zu haben. Und selbstverständlich ist das kein Exposed Host, sondern sitzt hinter einer FW.

    Und an Duplicate Hänk: NAT geht hier doch, genau so wie ich es mir vorgestellt habe. Ohne Portnummer komme ich auf die native NAS, mit Portnummern aud den Container. Ob ich das durchleite muss ich natürlich am Router einstellen, und den mach ich nur auf wenn, es nötig ist.