Server-Administration

Aus Tuxipedia

Collabora und Nextcloud hinter einem Reverse Proxy – das Hairpin-NAT-Problem

Hintergrund

Hairpin-NAT (auch: NAT Loopback) beschreibt ein Netzwerk-Phänomen, bei dem Datenpakete aus einem lokalen Netz heraus ins Internet geroutet werden – obwohl Absender und Empfänger im selben lokalen Netz sitzen. Der Weg biegt sich wie eine Haarnadel zurück. Ursache ist der NAT-Router (z.B. eine FritzBox), der interne IP-Adressen in die öffentliche IP übersetzt. Spricht ein Gerät intern die öffentliche Domain an, verlässt der Traffic das lokale Netz, durchläuft den Router, und kommt von außen zurück. Als Absender erscheint dann die öffentliche IP – nicht die interne.

Das Problem

Wer Nextcloud und Collabora (CODE) in getrennten Docker-Containern betreibt und beide hinter einem Reverse Proxy (z.B. Caddy, nginx, Traefik) versteckt, stößt früher oder später auf dieses Phänomen:

  • Office-Dokumente werden heruntergeladen statt geöffnet
  • Oder: „Laden des Dokuments fehlgeschlagen – Unautorisierter WOPI-Host"
  • Die Nextcloud-Logs zeigen: WOPI request denied from <externe IP>

Die externe IP des Servers landet in den Logs – obwohl Collabora und Nextcloud im selben Docker-Netz sitzen.

Ursache

Collabora bekommt vom Browser eine WOPI-URL mit der öffentlichen Domain:

https://nextcloud.example.com/index.php/apps/richdocuments/wopi/files/...

Collabora löst diese Domain auf – und landet bei der öffentlichen IP des Servers. Der Request verlässt das Docker-Netz, geht über den Router, kommt von außen zurück, und der Reverse Proxy leitet ihn an Nextcloud weiter.

Nextcloud sieht als Absender die externe IP – nicht die interne Docker-IP von Collabora. Die WOPI-Allowlist (172.x.x.x/16) matcht nicht. Zugriff verweigert.

Das nennt sich Hairpin-NAT (auch: NAT Loopback) – Traffic verlässt das lokale Netz und kommt von außen zurück, obwohl Quelle und Ziel im selben Netz sitzen.

Lösung

1. Docker-Netz auf festes Subnet festnageln

Docker vergibt Subnets dynamisch. Nach einem Neustart kann sich die IP-Range ändern. Daher das Netz einmalig mit festem Subnet anlegen:

<syntaxhighlight lang="bash"> docker network create \

 --driver=bridge \
 --subnet=172.20.0.0/16 \
 my-network

</syntaxhighlight>

Ein Script dafür anlegen damit es nach Neuinstallation reproduzierbar ist:

<syntaxhighlight lang="bash">

  1. !/bin/bash
  2. create-network.sh

docker network create \

 --driver=bridge \
 --subnet=172.20.0.0/16 \
 my-network

</syntaxhighlight>

2. Nextcloud eine feste IP geben

In der docker-compose.yml von Nextcloud:

<syntaxhighlight lang="yaml"> services:

 nextcloud:
   # ... weitere Konfiguration ...
   networks:
     my-network:
       ipv4_address: 172.20.0.10

</syntaxhighlight>

3. Collabora die interne Nextcloud-IP beibringen

Mit extra_hosts in der docker-compose.yml von Collabora – damit Collabora die öffentliche Domain intern auflöst statt den Umweg über das Internet zu nehmen:

<syntaxhighlight lang="yaml"> services:

 collabora:
   # ... weitere Konfiguration ...
   extra_hosts:
     - "nextcloud.example.com:172.20.0.10"
   networks: [my-network]

</syntaxhighlight>

Jetzt löst Collabora nextcloud.example.com intern auf 172.20.0.10 auf – kein Umweg über Router und Internet.

4. WOPI-Allowlist in Nextcloud setzen

<syntaxhighlight lang="bash"> docker exec nextcloud occ config:app:set richdocuments wopi_allowlist --value="172.20.0.0/16" </syntaxhighlight>

Prüfen ob der Wert gesetzt ist:

<syntaxhighlight lang="bash"> docker exec nextcloud occ config:app:get richdocuments wopi_allowlist </syntaxhighlight>

5. Collabora-Umgebungsvariablen

In der docker-compose.yml:

<syntaxhighlight lang="yaml"> environment:

 - aliasgroup1=https://nextcloud.example.com
 - domain=^nextcloud\.example\.com(:443)?$
 - extra_params=--o:ssl.enable=false --o:ssl.termination=true --o:logging.level=warning

</syntaxhighlight>

Caddy-Konfiguration

Für Collabora nur die nötigen Endpunkte von außen erreichbar machen, alles andere blocken:

<syntaxhighlight lang="caddy"> collabora.example.com {

 @allowed path /browser/* /hosting/capabilities /hosting/discovery /cool/* /lool/*
 handle @allowed {
   reverse_proxy collabora:9980
 }
 respond 403

} </syntaxhighlight>

Für Nextcloud die echte Client-IP weiterreichen:

<syntaxhighlight lang="caddy"> nextcloud.example.com {

 reverse_proxy nextcloud:443 {
   transport http {
     tls_insecure_skip_verify
   }
   header_up X-Real-IP {remote_ip}
 }

} </syntaxhighlight>

Zusammenfassung

Problem Lösung
Externes Routing trotz internem Docker-Netz Festes Subnet beim Netz-Anlegen
Collabora löst Nextcloud-Domain extern auf extra_hosts mit fester Nextcloud-IP
Nextcloud lehnt WOPI-Anfragen ab WOPI-Allowlist auf Docker-Subnet setzen
IP ändert sich bei Container-Neustart Feste IP für Nextcloud-Container vergeben

Warum das in der offiziellen Dokumentation fehlt

Nextcloud dokumentiert die WOPI-Allowlist. Collabora dokumentiert aliasgroup1. Aber niemand erklärt was passiert wenn beide hinter demselben Reverse Proxy sitzen und Collabora intern auf Nextcloud zugreifen muss.

Der typische Forenverlauf:

  1. „WOPI unauthorized" → „trag die IP ein"
  2. „Welche IP?" → Schweigen
  3. Drei Seiten später ungelöst
  4. Thread stirbt

Dieser Artikel soll das ändern.

Siehe auch