Server-Administration
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">
- !/bin/bash
- 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:
- „WOPI unauthorized" → „trag die IP ein"
- „Welche IP?" → Schweigen
- Drei Seiten später ungelöst
- Thread stirbt
Dieser Artikel soll das ändern.
