Normale Ansicht

Es gibt neue verfügbare Artikel. Klicken Sie, um die Seite zu aktualisieren.
Ältere BeiträgeHaupt-Feeds

Mit einem Dualstack-Reverse-Proxy Internet-Protokolle verbinden

26. Februar 2024 um 06:00

Mit einem Dualstack-Proxy Internet-Protokolle verbinden beschrieb eine Möglichkeit, um von Hosts, welche ausschließlich über IPv6-Adressen verfügen, auf Ziele zugreifen zu können, die ausschließlich über IPv4-Adressen verfügen. In diesem Beitrag betrachte ich die andere Richtung.

Zu diesem Beitrag motiviert hat mich der Kommentar von Matthias. Er schreibt, dass er für den bei einem Cloud-Provider gehosteten Jenkins Build Server IPv4 deaktivieren wollte, um Kosten zu sparen. Dies war jedoch nicht möglich, da Kollegen aus einem Co-Workingspace nur mit IPv4 angebunden sind und den Zugriff verloren hätten.

Doch wie kann man nun ein IPv6-Netzwerk für ausschließlich IPv4-fähige Clients erreichbar machen, ohne für jeden Host eine IPv4-Adresse zu buchen? Dazu möchte ich euch anhand eines einfachen Beispiels eine mögliche Lösung präsentieren.

Vorkenntnisse

Um diesem Text folgen zu können, ist ein grundsätzliches Verständnis von DNS, dessen Resource Records (RR) und des HTTP-Host-Header-Felds erforderlich. Die Kenntnis der verlinkten Wikipedia-Artikel sollte hierfür ausreichend sein.

Umgebung

Zu diesem Proof of Concept gehören:

  • Ein Dualstack-Reverse-Proxy-Server (HAProxy) mit den DNS-RR:
    • haproxy.example.com. IN A 203.0.113.1
    • haproxy.example.com IN AAAA 2001:DB8::1
  • Zwei HTTP-Backend-Server mit den DNS-RR:
    • www1.example.com IN AAAA 2001:DB8::2
    • www2.example.com IN AAAA 2001:DB8::3
  • Zwei DNS-RR:
    • www1.example.com IN A 203.0.113.1
    • www2.example.com IN A 203.0.113.1
  • Ein Client mit einer IPv4-Adresse

Ich habe mich für HAProxy als Reverse-Proxy-Server entschieden, da dieser in allen Linux- und BSD-Distributionen verfügbar sein sollte und mir die HAProxy Maps gefallen, welche ich hier ebenfalls vorstellen möchte.

Der Versuchsaufbau kann wie folgt skizziert werden:

Ein Dualstack-Reverse-Proxy-Server (B) verbindet IPv4-Clients mit IPv6-Backend-Servern

HAProxy-Konfiguration

Für dieses Minimal-Beispiel besteht die HAProxy-Konfiguration aus zwei Dateien, der HAProxy Map hosts.map und der Konfigurationsdatei poc.cfg.

~]$ cat /etc/haproxy/conf.d/hosts.map 
www1.example.com	serversa
www2.example.com	serversb

Eine HAProxy Map besteht aus zwei Spalten. In der ersten Spalte stehen die FQDNs, welche vom HTTP-Client aufgerufen werden können. In der zweiten Spalte steht der Name des Backends aus der HAProxy-Konfiguration, welcher bestimmt, an welche Backend-Server eine eingehende Anfrage weitergeleitet wird. In obigem Beispiel werden Anfragen nach www1.example.com an das Backend serversa und Anfragen nach www2.example.com an das Backend serversb weitergeleitet.

Die HAProxy Maps lassen sich unabhängig von der HAProxy-Konfigurations-Datei pflegen und bereitstellen. Map-Dateien werden in ein Elastic Binary Tree-Format geladen, so dass ein Wert aus einer Map-Datei mit Millionen von Elementen ohne spürbare Leistungseinbußen nachgeschlagen werden kann.

Die HAProxy-Konfigurations-Datei poc.cfg für dieses Minimal-Beispiel ist ähnlich simpel:

~]$ cat /etc/haproxy/conf.d/poc.cfg 
frontend fe_main
	bind :80
	use_backend %[req.hdr(host),lower,map(/etc/haproxy/conf.d/hosts.map)]

backend serversa
	server server1 2001:DB8::1:80
backend serversb
	server server1 2001:DB8::2:80

In der ersten Zeile wird ein Frontend mit Namen fe_main definiert. Zeile 2 bindet Port 80 für den entsprechenden Prozess und Zeile 3 bestimmt, welches Backend für eingehende HTTP-Anfragen zu nutzen ist. Dazu wird der HTTP-Host-Header ausgewertet, falls notwendig, in Kleinbuchstaben umgewandelt. Mithilfe der Datei hosts.map wird nun ermittelt, welches Backend zu verwenden ist.

Die weiteren Zeilen definieren zwei Backends bestehend aus jeweils einem Server, welcher auf Port 80 Anfragen entgegennimmt. In diesem Beispiel sind nur Server mit IPv6-Adressen eingetragen. IPv4-Adressen sind selbstverständlich auch zulässig und beide Versionen können in einem Backend auch gemischt auftreten.

Kann eine HTTP-Anfrage nicht über die hosts.map aufgelöst werden, läuft die Anfrage in diesem Beispiel in einen Fehler. Für diesen Fall kann ein Standard-Backend definiert werden. Siehe hierzu den englischsprachigen Artikel Introduction to HAProxy Maps von Chad Lavoie.

Der Kommunikationsablauf im Überblick und im Detail

Der Kommunikationsablauf im Überblick

Von einem IPv4-Client aus benutze ich curl, um die Seite www1.example.com abzurufen:

~]$ curl -4 -v http://www1.example.com
* processing: http://www1.example.com
*   Trying 203.0.113.1:80...
* Connected to www1.example.com (203.0.113.1) port 80
> GET / HTTP/1.1
> Host: www1.example.com
> User-Agent: curl/8.2.1
> Accept: */*
> 
< HTTP/1.1 200 OK
< server: nginx/1.20.1
< date: Sat, 06 Jan 2024 18:44:22 GMT
< content-type: text/html
< content-length: 5909
< last-modified: Mon, 09 Aug 2021 11:43:42 GMT
< etag: "611114ee-1715"
< accept-ranges: bytes
< 
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">

<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en">
	<head>
		<title>Test Page for the HTTP Server on Red Hat Enterprise Linux</title>

Der FQDN www1.example.com wird mit der IPv4-Adresse 203.0.113.1 aufgelöst, welche dem Host haproxy.example.com gehört. Bei der Zeile Host: www1.example.com handelt es sich um den HTTP-Host-Header, welchen der HAProxy benötigt, um das richtige Backend auszuwählen.

Es ist zu sehen, dass wir eine Antwort von einem NGINX-HTTP-Server erhalten. Der HTML-Quelltext wurde gekürzt.

Damit ist es gelungen, von einem IPv4-Client eine Ressource abzurufen, die von einem IPv6-Server bereitgestellt wird.

Im Access-Log des Backend-Servers mit der IPv6-Adresse 2001:DB8::2 sieht man:

2001:DB8::1 - - [06/Jan/2024:19:44:22 +0100] "GET / HTTP/1.1" 200 5909 "-" "curl/8.2.1" "192.0.2.1"

Die Anfrage erreicht den Backend-Server von der IPv6-Adresse des haproxy.example.com (2001:DB8::1). Die am Ende der Zeile zu sehende IPv4-Adresse (192.0.2.1) gehört dem IPv4-Client, von dem ich die Anfrage gesendet habe.

Gedanken zur Skalierung

In diesem Beispiel sind die Server www1.example.com und www2.example.com über ihre IPv6-Adressen direkt erreichbar. Nur die Client-Anfragen von IPv4-Clients laufen über den Reverse-Proxy. Wenn man es wünscht, kann man selbstverständlich sämtliche Anfragen (von IPv4- und IPv6-Clients) über den Reverse-Proxy laufen lassen.

In kleinen Umgebungen kann man einen Reverse-Proxy wie HAProxy zusammen mit Squid (vgl. Artikel Mit einem Dualstack-Proxy Internet-Protokolle verbinden) auf einem Host laufen lassen. Selbstverständlich kann man sie auch auf separate Hosts verteilen.

Hochverfügbarkeit lässt sich auch hier mit keepalived nachrüsten:

Abschließende Gedanken

Die Internet-Protokolle IPv4 und IPv6 werden wohl noch eine ganze Zeit gemeinsam das Internet bestimmen und parallel existieren. Ich bin mir sogar sicher, dass ich das Ende von IPv4 nicht mehr miterleben werde. Dualstack-(Reverse)-Proxy-Server stellen eine solide und robuste Lösung dar, um beide Welten miteinander zu verbinden.

Sicher bleiben noch ausreichend Herausforderungen übrig. Ich denke da nur an Firewalls, Loadbalancer, NAT und Routing. Und es werden sich auch Fälle finden lassen, in denen Proxyserver nicht infrage kommen. Doch mit diesen Herausforderungen beschäftige ich mich dann in anderen Artikeln.

Quellen und weiterführende Links

Mit einem Dualstack-Proxy Internet-Protokolle verbinden

12. Februar 2024 um 06:00

Stellt euch vor, ihr habt eine Menge von Servern, welche ausschließlich über IPv6-Adressen verfügen und deshalb keine Dienste nutzen können, welche nur über IPv4 bereitgestellt werden. Wer sich dies nicht vorstellen mag, findet in „IPv6… Kein Anschluss unter dieser Nummer“ ein paar Beispiele dafür.

Was kann man nun tun, damit diese IPv6-only-Hosts dennoch mit der IPv4-only-Welt kommunizieren können?

Eine mögliche Lösung ist die Nutzung eines Dualstack-Proxy-Servers. Das ist ein Server, welcher über Adressen beider Internet-Protokoll-Versionen verfügt und so stellvertretend für einen IPv6-Host mit einem IPv4-Host kommunizieren kann. Das folgende Bild veranschaulicht den Kommunikationsablauf:

Ablauf der Netzwerkkommunikation eines IPv6-Hosts mit einem IPv4-Host über einen Dualstack-Proxy-Server

Im Bild ist zu sehen:

  1. Wie IPv6-Host A eine Verbindung über IPv6 zum Proxy-Server B aufbaut und diesem bspw. die gewünschte URL mitteilt
  2. Der Proxy-Server B baut nun seinerseits eine IPv4-Verbindung zu IPv4-Host C auf, welcher die gewünschten Inhalte bereitstellt
  3. IPv4-Host C sendet seine Antwort über IPv4 an den Proxy-Server
  4. Der Proxy-Server sendet die gewünschten Inhalte anschließend via IPv6 an den IPv6-Host A zurück
Screencast zur Demonstration der Proxy-Nutzung

Das obige Video demonstriert die Nutzung eines Proxy-Servers durch den Abruf einer Demo-Seite mit curl:

  1. Mit dem host-Kommando wird gezeigt, dass für die Demo-Seite kein AAAA-Record existiert; die Seite ist also nicht via IPv6 erreichbar
  2. Mit dem ip-Kommando wird geprüft, dass der Host auf dem Interface ens18 ausschließlich über IPv6-Adressen verfügt
  3. Ohne Proxy ist die Demo-Seite nicht abrufbar
  4. Erst durch Nutzung des Proxys kann die Seite abgerufen werden

Funktioniert das auch von IPv4 nach IPv6?

Ja. Entscheidend ist, dass der verwendete Proxy beide IP-Versionen unterstützt.

Welcher Proxy ist empfehlenswert?

Der Proxy-Server muss beide IP-Versionen beherrschen. Ich persönlich bevorzuge Squid. Dieser ist in so gut wie allen Linux-Distributionen verfügbar, weit verbreitet, robust und selbstverständlich Freie Software.

Sind damit alle Herausforderungen bewältigt?

Für eine Virtualisierungs-Umgebung mit einer IPv4-Adresse und einem /64-IPv6-Netzsegment funktioniert diese Lösung gut. Sie funktioniert auch in jeder anderen Umgebung, wie gezeigt. Man beachte jedoch, dass man mit nur einem Proxy einen Single-Point-of-Failure hat. Um diesem zu begegnen, kann man Squid mit keepalived hochverfügbar gestalten.

Keepalived ist ebenfalls Freie Software. Sie kostet kein Geld, erhöht jedoch die Komplexität der Umgebung. Verfügbarkeit vs. Komplexität möge jeder Sysadmin selbst gegeneinander abwägen.

Wie mache ich meine IPv6-Dienste für IPv4-User erreichbar, die keinen Proxy haben?

Das Stichwort lautet Reverse-Proxy. Ein Artikel dazu erscheint in Kürze in diesem Blog. ;-)

Weiterführende Quellen und Links

WhatsApp ab sofort mit Proxy-Option – Sperren umgehen

Von: jdo
09. Januar 2023 um 08:51

Insbesondere in restriktiven Ländern sorgen Sperren immer wieder für Ärger. Sie schränken Meinungsfreiheit ein und für Reisende kann es ebenfalls problematisch sein, mit Verwandten und Freunden in Kontakt zu bleiben. Deswegen gibt es ab sofort auch bei WhatsApp Proxy-Unterstützung. Mit dem richtigen Proxy kannst Du WhatsApp also auch dann nutzen, wenn die App eigentlich durch eine Firewall oder andere Maßnahmen gesperrt ist. Dein Datenverkehr wird dann über einen sicheren Server geleitet und umgeht damit die Sperren von ISPs, Regierungen und […]

Der Beitrag WhatsApp ab sofort mit Proxy-Option – Sperren umgehen ist von bitblokes.de.

IP-Adresse verbergen – so geht es Schritt für Schritt

Von: jdo
03. Juni 2022 um 14:00

Du willst Deine echte IP-Adresse verbergen? Das muss übrigens keinen dubiosen Hintergrund haben. Es gibt viele Gründe, warum Du Deine IP-Adresse verstecken möchtest. Ein Grund könnte sein, dass Du Deinen echten Standort verbergen willst, um Geoblocking zu umgehen. Am einfachsten verschleierst Du Deine IP-Adresse mit einem guten VPN, etwa NordVPN*. Ein weiterer Grund sind Sicherheitsaspekte. Ist Deine reale IP-Adresse nicht bekannt, bist Du weniger anfällig für Cyber-Angriffe. Versteckst Du Deine IP-Adresse, kannst Du damit auch anonym im Internet surfen. Wie […]

Der Beitrag IP-Adresse verbergen – so geht es Schritt für Schritt ist von bitblokes.de.

Nextcloud im Container — Teil 3: Mit Reverse-Proxy

28. Februar 2022 um 06:00

In diesem Teil beschreibe ich die Konfiguration von NGINX als Reverse-Proxy für mein Wochenend-Projekt „Nextcloud im Container“. Und was so langweilig klingt, wie lediglich die Direktive proxy_pass in die NGINX-Konfiguration einzufügen, dauerte dann doch überraschend lange.

Darüber hinaus dokumentiere ich die Konfiguration von fail2ban, um die Anmeldemaske der Nextcloud vor Brute-Force-Angriffen zu schützen.

Falls ihr Teil 1 und Teil 2 dieser Reihe noch nicht kennt, empfehle ich euch, diese Teile zuerst zu lesen.

Die Fehlschläge

Bevor ich zur aktuellen Konfig komme, möchte ich kurz die Fehlschläge auf dem Weg dorthin festhalten.

Nextcloud im Unterverzeichnis nicht so einfach wie gedacht

Auf meinem Server läuft bereits ein Dienst, welcher unter der URL https://www.example.com/service1 erreichbar ist. Mir gefiel die Idee, die Nextcloud unter einer URL wie https://www.example.com/service2 erreichbar zu machen.

Die Dokumentation des Container-Repos [3] ist in meinen Augen zu kurz geraten und reicht für eine erfolgreiche Konfiguration längst nicht aus.

Nachdem ich einiges über die Generierung von Back-to-URLs und Redirects gelesen und im Nextcloud-Forum gestöbert hatte, ließ ich die Idee fallen. Ich warte mal ab, wie sich Issue #401 entwickelt. Vielleicht greife ich die Idee später nochmal auf.

Falsche Back-to-URLs und Protokoll-Probleme

Im nächsten Versuch, sollte Nextcloud unter einer eigenen Domain wie nextcloud.example.com erreichbar sein. Doch auch hier klemmte es zunächst. Zuerst stolperte ich in den bekannten Untrusted-Domain-Fehler.

access-through-untrusted-domain-error.png
Bekannte Fehlermeldung, wenn trusted_domains in config.php nicht korrekt gesetzt ist.

Diesen Fehler konnte ich schnell abstellen, da ich lediglich vergessen hatte die Variable NEXTCLOUD_TRUSTED_DOMAINS mit einem Wert zu belegen. Als Wert ist der FQDN einzutragen, unter dem die Nextcloud erreichbar sein soll. Dieser ist explizit anzugeben, da der Apache-Prozess innerhalb des Nextcloud-Containers den FQDN, auf den der NGINX-Reverse-Proxy lauscht und welcher im HTTP-Header übertragen wird, nicht kennt.

Des Weiteren musste ich noch die Variablen NEXTCLOUD_OVERWRITEPROTOCOL und NEXTCLOUD_OVERWRITECLIURL in vars/main.yml mit Werten belegen, um die entsprechenden Umgebungsvariablen für die Container-Instanz zu setzen (vgl. [3]). Dies ist notwendig, da die Anwendung im Nextcloud-Container andernfalls Back-to-URLs für das HTTP-Protokoll generiert. Versucht der Browser diese aufzurufen, erscheint ein Fehler oder man landet in einer endlosen Redirect-Schleife.

Nachdem ich die Nextcloud mit Hilfe der Ansible-Rolle [2] erneut deployt habe, war der Login-Screen erreichbar:

login-screen.png
Nextcloud-Login-Screen

Der Weg hierher war für meinen Geschmack aufwändiger als er hätte sein müssen. Nur durch Lektüre und Recherche der Quellen unter [4], [5] und [6] konnte ich mich von Problem zu Problem hangeln und diese lösen. Hier ist in meinen Augen noch Raum für Verbesserungen.

Die aktuell funktionierende Konfiguration

Meine NGINX-vHost-Konfiguration habe ich mir mithilfe von [4], [5] und [6] zusammengesucht und bin bei folgender Konfig gelandet (es werden nur relevante Abschnitte wiedergegeben):

server {
	listen 80;
	listen [::]:80;
	server_name nextcloud.example.com;
	root /var/www/nextcloud.example.com;
	index index.html;
[...]
	return 301 https://$server_name$request_uri;
	location ^~ /.well-known/acme-challenge/ {
	default_type "text/plain";
	root /var/www/nextcloud.example.com;
	}
	location = /.well-known/acme-challenge/ {
	return 404;
	}
}
server {
    # Listen on Port 443
    listen 443 ssl http2;
    listen [::]:443 ssl http2;
    server_name nextcloud.example.com;
[...]
    root /var/www/nextcloud.example.com;
[...]
	location ^~ /.well-known/acme-challenge/ {
	default_type "text/plain";
	root /var/www/nextcloud.example.com;
	}
	location = /.well-known/acme-challenge/ {
	return 404;
	}

        location / {
	proxy_set_header Host $host;
	proxy_set_header X-Forwarded-Proto $scheme;
	proxy_set_header X-Real-IP $remote_addr;
	proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
	add_header Front-End-Https on;
       	proxy_pass http://127.0.0.1:40231;
        }

	location /.well-known/carddav{
		return 301 $scheme://$host/remote.php/dav;
	}

	location /.well-known/caldav {
		return 301 $scheme://$host/remote.php/dav;
	}
}

Ob dies eine gute Konfiguration ist, mag ich nicht beurteilen. Sie funktioniert zumindest. Die Nextcloud ist erreichbar und über die Weboberfläche können weitere Einstellungen vorgenommen, Nutzerkonten erstellt und Apps installiert werden.

Fail2ban für Nextcloud

Nun steht die Nextcloud mit ihrer Login-Maske im Wind. Sie stellt damit ein schönes Ziel für Brute-Force-Angriffe dar. Um es den Angreifern nicht zu leicht zu machen, habe ich für den Nextcloud-Admin keinen einfach zu erratenen Namen wie Admin, Nextcloud-Admin oder meinen Namen verwendet. Um Angreifer weiter auszubremsen, konfiguriere ich fail2ban. Wie dies installiert wird, schlagt bitte in der Dokumentation eurer Distribution nach. Ich gehe hier nicht auf die Installation ein.

Damit fail2ban fehlgeschlagene Anmeldeversuche erkennt, habe ich die Datei /etc/fail2ban/filter.d/filter.d/jk_nextcloud.conf mit folgendem Inhalt erstellt:

[Definition]
_groupsre = (?:(?:,?\s*"\w+":(?:"[^"]+"|\w+))*)
failregex = ^\{%(_groupsre)s,?\s*"remoteAddr":"<HOST>"%(_groupsre)s,?\s*"message":"Login failed:
            ^\{%(_groupsre)s,?\s*"remoteAddr":"<HOST>"%(_groupsre)s,?\s*"message":"Trusted domain error.
datepattern = ,?\s*"time"\s*:\s*"%%Y-%%m-%%d[T ]%%H:%%M:%%S(%%z)?"

Dieser Filter wird in der Datei /etc/fail2ban/jail.d/jk_nextcloud.local referenziert:

[jk_nextcloud]
backend = auto
enabled = true
port = 80,443
protocol = tcp
filter = jk_nextcloud
maxretry = 3
bantime = 86400
findtime = 43200
logpath = /home/tronde/.local/share/containers/storage/volumes/nc_data/_data/nextcloud.log

Wenn innerhalb der findtime von 43200 Sekunden von einer IP-Adresse mehr als drei fehlgeschlagene Anmeldeversuche (maxretry) registriert werden, wird die entsprechede IP-Adresse für 86400 Sekunden (bantime) gesperrt. Eine Statusabfrage ist wie folgt möglich:

$ sudo fail2ban-client status jk_nextcloud
[sudo] password for tronde: 
Status for the jail: jk_nextcloud
|- Filter
|  |- Currently failed:	1
|  |- Total failed:	5
|  `- File list:	/home/tronde/.local/share/containers/storage/volumes/nc_data/_data/nextcloud.log
`- Actions
   |- Currently banned:	0
   |- Total banned:	1
   `- Banned IP list:

Es ist zu erkennen, dass aktuell keine IP-Adresse gesperrt ist. In der Vergangenheit wurde jedoch bereits eine IP gebannt.

Für mich stellt fail2ban einen Baustein zur Sicherung der Nextcloud bereit. Zusätzlich werde ich eine Zwei-Faktor-Authentisierung konfigurieren, um die Sicherheit weiter zu steigern.

Zusammenfassung

An diesem Punkt meines Wochenend-Projekts kann ich eine Nextcloud-Instanz mit meiner Ansible-Rolle deployen und hinter einem Reverse-Proxy nutzen. Bisher schützt fail2ban vor Brute-Force-Angriffen. Zukünftig wird jedoch eine Zwei-Faktor-Authentisierung diesen Schutz verstärken.

Eine lauffähige Konfiguration zu erstellen, hat dabei länger gedauert, als ich mir vorgestellt habe. Dabei hat mir missfallen, dass dies nicht mit der Dokumentation allein gelang, sondern das Forum [5] und die Internetsuchmaschine meines geringsten Misstrauens zurate gezogen werden mussten. Damit ist dieses Projekt jedoch bei weitem kein Einzelfall.

307 offene Issues (Stand 05.02.2022) zeugen davon, dass hier noch längst nicht alles rund läuft. Von der Idee, dass es sich hierbei um ein Fire-and-Forget-Projekt handeln könnte, verabschiede ich mich lieber. So bin ich auch gleich in das unter [7] beschriebene Problem getreten. Erfreulicher Weise hat die dort beschriebene Lösung funktioniert, so dass meine Cloud mir jetzt E-Mails senden kann. Ich werde mir Gedanken machen, wie die entsprechenden Abschnitte in der Dokumentation verbessert werden können und dem Projekt einen Pull-Request senden. Mal schauen wie man darauf reagiert.

Damit sind die in Teil 1 formulierten Ziele 1-3 erreicht. In Teil 4 beschäftige ich mich mit einigen weiteren Steinen, über die ich gestolpert bin, bevor ich mich dann in Teil 5 dem Thema Backup & Recovery widme.

Quellen und weiterführende Links

  1. Nextcloud im Container — Teil 1: Der Plan
  2. Nextcloud im Container — Teil 2: Die Ansible-Rolle
  3. Using the apache image behind a reverse proxy and auto configure server host and protocol
  4. https://github.com/nextcloud/docker
  5. https://help.nextcloud.com/
  6. https://docs.nextcloud.com/server/latest/admin_manual/
  7. Email settings gets wrong senEmail settings gets wrong sender domain, fails due to not RFC compliant
❌
❌