Nginx auf einem VPS + FRP über Tailscale
Mit dieser Anleitung wird eine auf ZimaOS laufende Nextcloud über eine normale öffentliche HTTPS-Domain erreichbar gemacht, ohne am privaten Internetanschluss eingehende Ports freizugeben.
Öffentliche Benutzer verbinden sich ausschließlich mit dem VPS. Dort nimmt Nginx die HTTPS-Verbindung entgegen. FRP transportiert die Anfrage zum Heimnetz, wobei die Verbindung zwischen frpc und frps durch das private Tailscale-Netz geführt wird. Vom FRP-Client auf ZimaOS geht die Anfrage anschließend an die lokale Nextcloud-Instanz.
Vorwort
Ich nutze die Kernarchitektur hinter dieser Anleitung bereits seit einiger Zeit in meinem eigenen Homelab: Nginx und FRP laufen auf einem öffentlichen VPS, während die FRP-Verbindung über Tailscale in meine private Proxmox-Umgebung geführt wird.
Für dieses Tutorial habe ich dasselbe Konzept auf ZimaOS übertragen. Da sich bei neueren Versionen von Tailscale, FRP und den verwendeten Container-Images einige Konfigurationsdetails geändert haben, habe ich den Aufbau aktualisiert und den vollständigen Verbindungsweg vor dem Schreiben der Anleitung erneut simuliert.
Dieses Tutorial verbindet damit eine bewährte Architektur mit einer aktualisierten Umsetzung für ZimaOS. IP-Adressen, Ports, Containernamen und die Proxy-Einstellungen von Nextcloud müssen an die jeweilige Umgebung angepasst werden.
Hinweis
Die Konfigurationsdateien wurden auf gültige YAML-, TOML- und Nginx-Syntax geprüft. Zusätzlich wurde der vollständige HTTP-Verbindungsweg über Nginx, einen lokalen FRP-Port, einen SOCKS5-Transport und einen internen Webdienst simuliert.
Einige Werte hängen jedoch zwangsläufig von der konkreten ZimaOS- und Nextcloud-Installation ab. Das betrifft insbesondere den veröffentlichten Nextcloud-Port, den Containernamen und die Adresse, die Nextcloud später als direkten Proxy sieht.
Was dieser Aufbau löst
Eine lokal betriebene Nextcloud benötigt für den öffentlichen Zugriff üblicherweise mindestens eine der folgenden Voraussetzungen:
-
eine eingehende Portfreigabe am Router,
-
eine öffentlich erreichbare IPv4-Adresse,
-
eine DynDNS-Lösung,
-
oder einen externen Relay-Dienst.
Bei diesem Aufbau wird am privaten Anschluss nichts eingehend veröffentlicht. Die gesamte Verbindung aus dem Heimnetz wird ausgehend aufgebaut.
Auch die Benutzer der Nextcloud benötigen kein Tailscale. Sie öffnen die Instanz ganz normal über ihre öffentliche Domain, beispielsweise:
cloud.example.com
Der VPS ist der einzige öffentlich erreichbare Einstiegspunkt.
Architektur
Internet
│
▼
Öffentliche Domain / DNS
cloud.example.com
│
▼
VPS
├─ Nginx
│ └─ HTTPS, Zertifikat und Reverse Proxy
│
├─ FRP-Server (frps)
│ └─ lokaler Proxy-Port 127.0.0.1:18080
│
└─ Tailscale
│
│ private Tailscale-Verbindung
▼
ZimaOS
├─ Tailscale-Container
├─ FRP-Client (frpc)
│
▼
Lokale Nextcloud-App
Der tatsächliche Datenweg lautet:
Internet
→ öffentliche Domain
→ Nginx auf dem VPS
→ lokaler FRP-Port auf dem VPS
→ frps
→ Tailscale
→ frpc auf ZimaOS
→ lokale Nextcloud
Am privaten Router existiert dabei keine eingehende NAT- oder Firewall-Regel für Nextcloud.
Aufgaben der einzelnen Komponenten
Nginx auf dem VPS
Nginx bildet den öffentlichen Einstiegspunkt und übernimmt:
-
die öffentliche Domain,
-
das TLS-Zertifikat,
-
die Weiterleitung von HTTP auf HTTPS,
-
die erforderlichen Proxy-Header,
-
Upload-Limits und Timeouts,
-
sowie bei Bedarf zusätzliche Schutzmechanismen oder Rate-Limits.
FRP
FRP übernimmt die eigentliche Veröffentlichung des internen Dienstes:
-
frpcbaut die Verbindung aus dem Heimnetz aktiv auf, -
frpsstellt auf dem VPS einen lokalen Port bereit, -
Nginx leitet öffentliche Anfragen an diesen lokalen Port,
-
FRP transportiert die Verbindung zurück zur internen Nextcloud.
Tailscale
Tailscale stellt die private Netzwerkverbindung zwischen dem VPS und dem FRP-Client auf ZimaOS bereit.
Tailscale ersetzt FRP in diesem Aufbau nicht. Beide Komponenten erfüllen unterschiedliche Aufgaben:
-
Tailscale: private Erreichbarkeit zwischen VPS und ZimaOS
-
FRP: Veröffentlichung und Zuordnung des internen Dienstes
Tailscale im Userspace-Modus
Die Hauptvariante dieser Anleitung verwendet Tailscale innerhalb eines Containers im Userspace-Modus mit einem SOCKS5-Proxy.
Dadurch werden auf ZimaOS keine folgenden Berechtigungen benötigt:
-
/dev/net/tun -
NET_ADMIN -
SYS_MODULE -
Änderungen am Netzwerk des ZimaOS-Hosts
Der Nachteil kann ein geringerer Datendurchsatz gegenüber dem Kernel-Modus sein. Eine alternative Kernel-Konfiguration ist am Ende der Anleitung beschrieben.
Beispielwerte
Alle folgenden Werte sind Beispiele und müssen ersetzt werden.
| Einstellung | Beispiel |
|---|---|
| Öffentliche Nextcloud-Domain | cloud.example.com |
| Öffentliche IPv4-Adresse des VPS | 203.0.113.10 |
| Tailscale-IP des VPS | 100.64.0.10 |
| Lokale IP-Adresse von ZimaOS | 192.168.1.50 |
| Veröffentlichter Nextcloud-Port | 8080 |
| FRP-Steuerport | 7000 |
| Lokaler FRP-Upstream-Port auf dem VPS | 18080 |
| Tailscale-Gerätename | zimaos-frpc |
Für ZimaOS sollte im Router eine DHCP-Reservierung oder eine feste IP-Adresse eingerichtet werden.
Für die folgenden Befehle wird die Beispieldomain als Variable verwendet:
NEXTCLOUD_DOMAIN="cloud.example.com"
Teil 1: Nextcloud auf ZimaOS vorbereiten
1. Nextcloud installieren
In der ZimaOS-Weboberfläche den App Center öffnen und Nextcloud installieren.
Nach der Installation muss Nextcloud zunächst im lokalen Netzwerk funktionieren, beispielsweise unter:
http://192.168.1.50:8080
Der tatsächliche Port hängt von der verwendeten App-Center-Vorlage und den gewählten Einstellungen ab.
Erst fortfahren, wenn Nextcloud von einem anderen Gerät im lokalen Netzwerk erreichbar ist.
2. Lokalen Endpunkt notieren
Für die spätere FRP-Konfiguration werden folgende Werte benötigt:
ZIMAOS_LAN_IP=192.168.1.50
NEXTCLOUD_PORT=8080
Zusätzlich sollte in den Einstellungen der Nextcloud-App geprüft werden, welcher Host-Pfad für die Konfiguration und die persistenten Daten verwendet wird.
ZimaOS speichert persistente App-Daten üblicherweise unter:
/DATA/AppData/...
Der genaue Unterordner hängt von der installierten Nextcloud-Vorlage ab.
3. Terminalzugriff aktivieren
In ZimaOS den Terminal- oder SSH-Zugriff aktivieren:
Einstellungen
→ Entwicklermodus
→ SSH-Zugriff
Die Shell-Befehle in dieser Anleitung werden über SSH oder das Webterminal auf ZimaOS ausgeführt.
Teil 2: VPS vorbereiten
Die folgenden Befehle gehen von einem aktuellen Debian- oder Ubuntu-System auf dem VPS aus.
1. Nginx, Docker, Compose und Certbot installieren
sudo apt update
sudo apt install -y nginx docker.io docker-compose-plugin certbot python3-certbot-nginx
sudo systemctl enable --now nginx docker
Prüfen, ob Docker Compose verfügbar ist:
docker compose version
2. Tailscale auf dem VPS installieren
Tailscale entsprechend der oben verlinkten offiziellen Dokumentation auf dem VPS installieren und anschließend ausführen:
sudo tailscale up
Den im Terminal angezeigten Authentifizierungslink öffnen und den VPS mit dem eigenen Tailnet verbinden.
Anschließend die Tailscale-IP des VPS ausgeben:
tailscale ip -4
Beispiel:
VPS_TAILSCALE_IP=100.64.0.10
Diese Adresse wird später in der frpc.toml auf ZimaOS eingetragen.
3. FRP-Token erzeugen
sudo mkdir -p /opt/frps
openssl rand -hex 32 | sudo tee /opt/frps/token >/dev/null
sudo chmod 600 /opt/frps/token
sudo cat /opt/frps/token
Das Token sicher kopieren. Auf ZimaOS muss später exakt dasselbe Token gespeichert werden.
Das echte Token darf niemals in einem öffentlichen Beitrag, Screenshot oder Anhang erscheinen.
4. frps.toml erstellen
Datei anlegen:
/opt/frps/frps.toml
Inhalt:
bindAddr = "100.64.0.10"
bindPort = 7000
# Die durch FRP erzeugten Proxy-Ports sind nur lokal auf dem VPS erreichbar.
proxyBindAddr = "127.0.0.1"
auth.method = "token"
auth.tokenSource.type = "file"
auth.tokenSource.file.path = "/etc/frp/token"
# Nur FRP-Clients mit aktiviertem TLS akzeptieren.
transport.tls.force = true
# frpc darf ausschließlich den für Nextcloud vorgesehenen Port anlegen.
allowPorts = [
{ single = 18080 }
]
log.to = "console"
log.level = "info"
Die Adresse 100.64.0.10 durch die tatsächliche Tailscale-IP des VPS ersetzen.
Diese Konfiguration stellt sicher:
-
Port
7000ist nur über die Tailscale-IP des VPS erreichbar. -
Der durch FRP erzeugte Port
18080bindet ausschließlich an127.0.0.1. -
Der FRP-Client muss sich mit einem Token authentifizieren.
-
Der FRP-Client darf nur den freigegebenen Port
18080verwenden. -
Die FRP-Verbindung muss TLS verwenden.
5. frps als Container starten
Datei anlegen:
/opt/frps/docker-compose.yml
Inhalt:
services:
frps:
image: fatedier/frps:v0.70.1
container_name: frps
network_mode: host
restart: unless-stopped
command:
- -c
- /etc/frp/frps.toml
volumes:
- /opt/frps/frps.toml:/etc/frp/frps.toml:ro
- /opt/frps/token:/etc/frp/token:ro
Container starten:
cd /opt/frps
sudo docker compose up -d
sudo docker logs frps
Prüfen, ob der FRP-Steuerport korrekt gebunden wurde:
sudo ss -ltnp | grep ':7000'
Der Port muss auf der Tailscale-IP lauschen.
Er darf nicht an folgenden Adressen gebunden sein:
0.0.0.0:7000
öffentliche-vps-ip:7000
Teil 3: Tailscale- und FRP-App auf ZimaOS erstellen
1. Persistente Verzeichnisse anlegen
Auf ZimaOS:
sudo mkdir -p /DATA/AppData/zima-frp-tunnel/tailscale
sudo mkdir -p /DATA/AppData/zima-frp-tunnel/frpc
sudo chmod 700 /DATA/AppData/zima-frp-tunnel/frpc
2. FRP-Token speichern
Folgende Datei anlegen:
/DATA/AppData/zima-frp-tunnel/frpc/token
Das zuvor auf dem VPS erzeugte Token einfügen und anschließend die Berechtigungen setzen:
sudo chmod 600 /DATA/AppData/zima-frp-tunnel/frpc/token
3. frpc.toml erstellen
Datei anlegen:
/DATA/AppData/zima-frp-tunnel/frpc/frpc.toml
Inhalt:
serverAddr = "100.64.0.10"
serverPort = 7000
# Bei einem vorübergehenden Ausfall von VPS oder Tailscale weiter versuchen.
loginFailExit = false
auth.method = "token"
auth.tokenSource.type = "file"
auth.tokenSource.file.path = "/etc/frp/token"
transport.protocol = "tcp"
transport.tls.enable = true
# FRP-Verbindung durch den Tailscale-Userspace-SOCKS5-Proxy führen.
transport.proxyURL = "socks5://127.0.0.1:1055"
log.to = "console"
log.level = "info"
[[proxies]]
name = "zimaos-nextcloud"
type = "tcp"
# Lokaler Nextcloud-Endpunkt auf ZimaOS.
localIP = "192.168.1.50"
localPort = 8080
# frps legt diesen Port auf 127.0.0.1 des VPS an.
remotePort = 18080
healthCheck.type = "tcp"
healthCheck.timeoutSeconds = 3
healthCheck.maxFailed = 3
healthCheck.intervalSeconds = 10
Folgende Werte ersetzen:
-
serverAddr: Tailscale-IP des VPS -
localIP: lokale IP-Adresse von ZimaOS -
localPort: veröffentlichter Port der Nextcloud-App
4. Tailscale-Authentifizierungsschlüssel erstellen
In der Tailscale-Administrationsoberfläche einen Auth-Key für den ZimaOS-Tunnel-Container erstellen.
Empfohlene Eigenschaften:
-
vorab autorisiert,
-
nicht flüchtig,
-
nur dann wiederverwendbar, wenn dies für die eigene Wiederherstellungsstrategie erforderlich ist,
-
optional über ein Tag und die Tailscale-Zugriffsregeln eingeschränkt.
Der Auth-Key ist ein Geheimnis und darf nicht veröffentlicht werden.
5. Benutzerdefinierte App in ZimaOS importieren
In ZimaOS öffnen:
App Center
→ Install a Customized App
→ Import
Folgende Compose-Konfiguration einfügen:
services:
tailscale:
image: tailscale/tailscale:stable
container_name: zima-tunnel-tailscale
hostname: zimaos-frpc
restart: unless-stopped
environment:
TS_AUTHKEY: "HIER_DEN_TAILSCALE_AUTH_KEY_EINTRAGEN"
TS_HOSTNAME: "zimaos-frpc"
TS_STATE_DIR: "/var/lib/tailscale"
TS_AUTH_ONCE: "true"
TS_USERSPACE: "true"
TS_SOCKS5_SERVER: ":1055"
TS_ACCEPT_DNS: "false"
volumes:
- /DATA/AppData/zima-frp-tunnel/tailscale:/var/lib/tailscale
frpc:
image: fatedier/frpc:v0.70.1
container_name: zima-tunnel-frpc
network_mode: "service:tailscale"
depends_on:
- tailscale
restart: unless-stopped
command:
- -c
- /etc/frp/frpc.toml
volumes:
- /DATA/AppData/zima-frp-tunnel/frpc:/etc/frp:ro
Die App anschließend installieren.
Dieser Stack veröffentlicht auf ZimaOS bewusst keinen eingehenden Port. Beide Container bauen ausschließlich ausgehende Verbindungen auf.
6. Tailscale-Registrierung prüfen
In der Tailscale-Administrationsoberfläche sollte ein neues Gerät erscheinen:
zimaos-frpc
Auf ZimaOS die Logs des Tailscale-Containers prüfen:
docker logs zima-tunnel-tailscale
Danach die Logs des FRP-Clients prüfen:
docker logs zima-tunnel-frpc
Bei erfolgreicher Verbindung sollte der Proxy zimaos-nextcloud ohne Authentifizierungs- oder Verbindungsfehler gestartet werden.
7. Tailscale-Auth-Key nach der Registrierung entfernen
Der Zustand und die Geräteidentität von Tailscale werden persistent gespeichert unter:
/DATA/AppData/zima-frp-tunnel/tailscale
Nach der erfolgreichen ersten Registrierung den Eintrag TS_AUTHKEY aus der Compose-Konfiguration entfernen und die App neu starten.
Mit:
TS_AUTH_ONCE=true
und dem persistenten Statusverzeichnis sollte der Container seine Geräteidentität behalten.
Ein wiederverwendbarer Auth-Key darf nicht dauerhaft in der App-Konfiguration, in exportierten Dateien oder auf Screenshots verbleiben.
Teil 4: Privaten Tunnel prüfen
1. FRP-Port auf dem VPS kontrollieren
Nachdem frpc erfolgreich verbunden ist:
sudo ss -ltnp | grep ':18080'
Erwartete Bindung:
127.0.0.1:18080
Der Port darf nicht öffentlich gebunden sein:
0.0.0.0:18080
2. Upstream lokal auf dem VPS testen
curl -I http://127.0.0.1:18080
Eine Antwort mit beispielsweise 200, 301 oder 302 bestätigt, dass der private Verbindungsweg grundsätzlich funktioniert:
VPS
→ frps
→ Tailscale
→ frpc
→ Nextcloud
Auch eine Nextcloud-Meldung zu einer nicht vertrauenswürdigen Domain zeigt bereits, dass der Tunnel funktioniert. Die Domain-Konfiguration wird später korrigiert.
Teil 5: Öffentlichen DNS-Eintrag anlegen
Beim DNS-Anbieter einen A-Record erstellen:
cloud.example.com → 203.0.113.10
Als Ziel wird die öffentliche IPv4-Adresse des VPS verwendet.
Ein AAAA-Record sollte nur angelegt werden, wenn:
-
der VPS korrekt über IPv6 erreichbar ist,
-
Nginx über IPv6 lauscht,
-
und die Firewall entsprechend eingerichtet wurde.
DNS-Auflösung prüfen:
dig +short cloud.example.com
Teil 6: Nginx auf dem VPS konfigurieren
1. Nginx-Site anlegen
Datei erstellen:
/etc/nginx/sites-available/cloud.example.com
Zunächst folgende HTTP-Konfiguration verwenden:
server {
listen 80;
listen [::]:80;
server_name cloud.example.com;
client_max_body_size 10G;
location / {
proxy_pass http://127.0.0.1:18080;
proxy_http_version 1.1;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $remote_addr;
proxy_set_header X-Forwarded-Host $host;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_set_header X-Forwarded-Port $server_port;
proxy_request_buffering off;
proxy_buffering off;
proxy_connect_timeout 60s;
proxy_send_timeout 3600s;
proxy_read_timeout 3600s;
}
}
cloud.example.com durch die eigene Domain ersetzen.
Site aktivieren:
sudo ln -s /etc/nginx/sites-available/cloud.example.com \
/etc/nginx/sites-enabled/cloud.example.com
Konfiguration prüfen und Nginx neu laden:
sudo nginx -t
sudo systemctl reload nginx
2. TLS-Zertifikat abrufen
sudo certbot --nginx -d cloud.example.com
Bei der Abfrage die automatische Weiterleitung von HTTP auf HTTPS auswählen.
Certbot ergänzt anschließend:
-
den HTTPS-Listener,
-
die Zertifikatspfade,
-
und die Weiterleitung auf HTTPS.
Automatische Zertifikatserneuerung testen:
sudo certbot renew --dry-run
3. CalDAV- und CardDAV-Weiterleitungen ergänzen
Im HTTPS-server-Block vor location / ergänzen:
location = /.well-known/carddav {
return 301 https://$host/remote.php/dav/;
}
location = /.well-known/caldav {
return 301 https://$host/remote.php/dav/;
}
Im HTTPS-Block müssen die externen Werte für Protokoll und Port weitergegeben werden:
proxy_set_header X-Forwarded-Proto https;
proxy_set_header X-Forwarded-Port 443;
Danach erneut prüfen:
sudo nginx -t
sudo systemctl reload nginx
Teil 7: Nextcloud für die öffentliche Domain konfigurieren
1. Containernamen der Nextcloud ermitteln
Auf ZimaOS:
docker ps --format 'table {{.Names}}\t{{.Image}}\t{{.Ports}}' | grep -i nextcloud
Anschließend eine Variable setzen:
NC_CONTAINER="HIER_DEN_NEXTCLOUD_CONTAINERNAMEN_EINTRAGEN"
Je nach ZimaOS-App-Vorlage kann der Container anders heißen.
2. Öffentliche Domain zu trusted_domains hinzufügen
Zunächst vorhandene Einträge anzeigen:
docker exec -u www-data "$NC_CONTAINER" \
php occ config:system:get trusted_domains
Die öffentliche Domain am nächsten freien numerischen Index ergänzen:
docker exec -u www-data "$NC_CONTAINER" \
php occ config:system:set trusted_domains 1 \
--value="cloud.example.com"
Falls Index 1 bereits verwendet wird, den nächsten freien Index wählen.
Bei einigen Nextcloud-Templates muss der
occ-Befehl mit einem anderen Benutzer oder aus einem anderen Pfad ausgeführt werden. In diesem Fall die Angaben der verwendeten App-Vorlage prüfen.
3. Externe HTTPS-Adresse konfigurieren
Externes Protokoll setzen:
docker exec -u www-data "$NC_CONTAINER" \
php occ config:system:set overwriteprotocol \
--value="https"
Öffentliche Basisadresse für Kommandozeilen- und Hintergrundprozesse setzen:
docker exec -u www-data "$NC_CONTAINER" \
php occ config:system:set overwrite.cli.url \
--value="https://${NEXTCLOUD_DOMAIN}"
Da Nginx den ursprünglichen Host-Header weitergibt, ist overwritehost normalerweise nicht notwendig.
Nur wenn Nextcloud weiterhin einen falschen Hostnamen erzeugt:
docker exec -u www-data "$NC_CONTAINER" \
php occ config:system:set overwritehost \
--value="cloud.example.com"
Soll dieselbe Nextcloud zusätzlich weiterhin lokal über HTTP erreichbar bleiben, sollte statt globaler Überschreibungen gegebenenfalls overwritecondaddr verwendet werden.
4. Vertrauenswürdigen Proxy festlegen
Nginx übergibt die ursprüngliche Client-Adresse über:
X-Forwarded-For
Nextcloud verwendet diesen Header jedoch nur dann, wenn die unmittelbar verbindende Quelle in trusted_proxies eingetragen ist.
Da FRP auf der ZimaOS-Seite eine neue lokale Verbindung erzeugt, sieht Nextcloud normalerweise nicht die Tailscale-IP des VPS als direkten Kommunikationspartner. Häufig erscheint stattdessen eine Docker-Bridge- oder Gateway-Adresse.
Die tatsächlich von Nextcloud gesehene Quelladresse muss nach einem öffentlichen Testaufruf im Access-Log des Nextcloud-Webservers ermittelt werden.
Danach ausschließlich diese Adresse oder das kleinstmögliche erforderliche Subnetz eintragen:
docker exec -u www-data "$NC_CONTAINER" \
php occ config:system:set trusted_proxies 0 \
--value="HIER_DIE_TATSAECHLICHE_PROXY_IP_ODER_DAS_CIDR_EINTRAGEN"
Mögliche Beispiele:
172.18.0.1
172.18.0.0/24
Nicht verwenden:
0.0.0.0/0
Die genaue Adresse hängt von der installierten Nextcloud-Vorlage und der Docker-Netzwerkstruktur ab. Sie kann deshalb in einer allgemeinen Anleitung nicht fest vorgegeben werden.
5. Nextcloud-Konfiguration prüfen
docker exec -u www-data "$NC_CONTAINER" \
php occ config:list system
Die relevanten Werte sollten enthalten:
trusted_domains
trusted_proxies
overwriteprotocol = https
overwritehost = cloud.example.com # nur falls erforderlich
overwrite.cli.url = https://${NEXTCLOUD_DOMAIN}
Teil 8: Abschließender Funktionstest
Test direkt vom VPS
curl -I http://127.0.0.1:18080
Test aus einem externen Netzwerk
Nicht aus dem eigenen WLAN testen, sondern beispielsweise über Mobilfunk:
curl -I https://${NEXTCLOUD_DOMAIN}
Alternativ im Browser öffnen:
cloud.example.com
Folgende Punkte prüfen:
-
Das TLS-Zertifikat ist gültig.
-
Der Browser bleibt dauerhaft auf HTTPS.
-
Die Anmeldung funktioniert.
-
Dateien lassen sich hochladen.
-
Dateien lassen sich herunterladen.
-
WebDAV funktioniert.
-
Am privaten Router existiert keine Portfreigabe.
-
Nextcloud ist nicht direkt über den VPS-Port erreichbar.
-
Der FRP-Steuerport lauscht nicht auf der öffentlichen VPS-Adresse.
-
Der FRP-Upstream-Port ist ausschließlich an
127.0.0.1gebunden.
Für diese Anleitung durchgeführte Prüfung
Vor der Veröffentlichung wurden folgende Punkte geprüft:
-
Beide Docker-Compose-Dateien lassen sich als gültiges YAML einlesen.
-
Beide FRP-Konfigurationen lassen sich als gültiges TOML einlesen.
-
Die Nginx-Konfiguration besteht
nginx -t. -
Der vollständige HTTP-Pfad wurde lokal simuliert:
Nginx
→ ausschließlich lokal gebundener FRP-Port
→ ausgehende Reverse-Verbindung über einen SOCKS5-Endpunkt
→ interner HTTP-Dienst
Die Simulation lieferte eine erfolgreiche HTTP-Antwort und bestätigte die Weitergabe folgender Header:
Host
X-Real-IP
X-Forwarded-For
X-Forwarded-Host
X-Forwarded-Proto
X-Forwarded-Port
Umgebungsspezifisch und daher vor Ort zu prüfen sind:
-
das Importverhalten der benutzerdefinierten App in der verwendeten ZimaOS-Version,
-
die Tailscale-Registrierung und die eigenen Zugriffsregeln,
-
der tatsächliche Host-Port der verwendeten Nextcloud-App,
-
der genaue Nextcloud-Containername,
-
die konkrete Docker-Quelladresse für
trusted_proxies, -
sowie der reale Datendurchsatz bei großen und lang laufenden Übertragungen.
Sicherheitscheckliste
-
Am privaten Router existiert keine eingehende Portfreigabe.
-
Der VPS veröffentlicht nur die vorgesehenen Dienste, normalerweise
80/tcpund443/tcp. -
frps.bindAddrenthält die Tailscale-IP des VPS. -
frps.proxyBindAddrist auf127.0.0.1gesetzt. -
allowPortserlaubt ausschließlich den benötigten FRP-Port. -
FRP-Token-Authentifizierung ist aktiviert.
-
FRP-TLS ist erzwungen.
-
Das echte FRP-Token erscheint in keinem öffentlichen Beitrag oder Anhang.
-
Der Tailscale-Auth-Key wurde nach der ersten Registrierung entfernt.
-
Das Tailscale-Statusverzeichnis wird persistent gespeichert.
-
Nextcloud vertraut nur der tatsächlich benötigten Proxy-IP oder dem kleinsten erforderlichen Subnetz.
-
Für Nextcloud-Administratoren ist Zwei-Faktor-Authentifizierung aktiviert.
-
ZimaOS, Nextcloud, Nginx, Tailscale, FRP und das Betriebssystem des VPS werden regelmäßig aktualisiert.
-
Backups sind vorhanden.
-
Die Wiederherstellung wurde dokumentiert oder getestet.
Fehlerbehebung
Nginx meldet 502 Bad Gateway
Prüfen, ob der FRP-Port auf dem VPS vorhanden ist:
sudo ss -ltnp | grep ':18080'
Logs von frps prüfen:
sudo docker logs frps
Logs auf ZimaOS prüfen:
docker logs zima-tunnel-frpc
docker logs zima-tunnel-tailscale
Häufige Ursachen:
-
frpcist nicht verbunden. -
Das FRP-Token stimmt nicht überein.
-
Die Tailscale-IP des VPS ist falsch.
-
Eine Tailscale-Zugriffsregel blockiert TCP-Port
7000. -
localIPoderlocalPortin derfrpc.tomlist falsch. -
Die Nextcloud-App läuft nicht.
-
Der veröffentlichte Nextcloud-Port wurde geändert.
frpc kann frps nicht erreichen
Folgende Werte prüfen:
transport.protocol = "tcp"
transport.proxyURL = "socks5://127.0.0.1:1055"
Die FRP-Proxy-Einstellung funktioniert in diesem Aufbau nur mit einer TCP-Verbindung zu frps.
Außerdem prüfen, ob Tailscale den SOCKS5-Listener gestartet hat:
docker logs zima-tunnel-tailscale
Nextcloud meldet eine nicht vertrauenswürdige Domain
Die öffentliche Domain zu trusted_domains hinzufügen.
Beispiel:
cloud.example.com
Weiterleitungsschleife oder erzeugte HTTP-Links
Folgende Werte prüfen:
overwriteprotocol = https
overwrite.cli.url = https://${NEXTCLOUD_DOMAIN}
overwritehost = cloud.example.com # nur falls erforderlich
Nginx muss außerdem folgende Werte weitergeben:
X-Forwarded-Proto: https
X-Forwarded-Port: 443
Host: cloud.example.com
Uploads brechen ab
Nginx-Limits und Timeouts prüfen:
client_max_body_size 10G;
proxy_request_buffering off;
proxy_send_timeout 3600s;
proxy_read_timeout 3600s;
Zusätzlich die Upload-Limits von PHP und Nextcloud innerhalb der installierten App prüfen.
Nextcloud protokolliert nur die Proxy-Adresse
Die direkte Quelladresse ermitteln, die Nextcloud tatsächlich sieht, und ausschließlich diese Adresse oder das kleinste notwendige Subnetz in trusted_proxies eintragen.
Nicht pauschal alle privaten Netze oder alle IP-Adressen freigeben.
Der direkte Kommunikationspartner von Nextcloud befindet sich auf dem FRP- beziehungsweise Docker-Pfad. Es ist nicht automatisch die öffentliche oder die Tailscale-IP des VPS.
Tailscale erscheint nach jedem Neustart als neues Gerät
Prüfen, ob das persistente Verzeichnis korrekt eingebunden ist:
/DATA/AppData/zima-frp-tunnel/tailscale:/var/lib/tailscale
Außerdem müssen folgende Werte gesetzt sein:
TS_STATE_DIR=/var/lib/tailscale
TS_AUTH_ONCE=true
Optional: Tailscale im Kernel-Modus
Der Userspace-Modus ist einfacher zu importieren und benötigt keine erweiterten Netzwerkberechtigungen. Der Kernel-Modus kann jedoch einen höheren Durchsatz liefern.
Für die Umstellung sind folgende Änderungen erforderlich.
1. SOCKS5-Server entfernen
Aus der Compose-Konfiguration entfernen:
TS_SOCKS5_SERVER: ":1055"
2. Userspace-Modus deaktivieren
TS_USERSPACE: "false"
3. TUN-Gerät und Berechtigungen ergänzen
Beim Tailscale-Service ergänzen:
devices:
- /dev/net/tun:/dev/net/tun
cap_add:
- NET_ADMIN
- SYS_MODULE
4. SOCKS5-Proxy aus der FRP-Konfiguration entfernen
Aus frpc.toml löschen:
transport.proxyURL = "socks5://127.0.0.1:1055"
Da frpc weiterhin den Netzwerk-Namespace des Tailscale-Containers verwendet, kann der FRP-Client anschließend direkt zur Tailscale-IP des VPS verbinden.
Der Kernel-Modus sollte nur verwendet werden, wenn:
-
/dev/net/tunauf dem ZimaOS-Host verfügbar ist, -
die importierte App die erforderlichen Berechtigungen erhält,
-
und die Auswirkungen auf das Host-Netzwerk verstanden werden.
Weitere ZimaOS-Dienste veröffentlichen
Mit derselben Architektur lassen sich weitere interne Webdienste über den VPS veröffentlichen.
Für jeden zusätzlichen Dienst:
-
einen neuen, nur lokal gebundenen FRP-Port auf dem VPS auswählen,
-
diesen Port in
frps.allowPortsergänzen, -
einen weiteren
[[proxies]]-Block infrpc.tomlanlegen, -
eine zusätzliche Nginx-Site für die neue Domain erstellen,
-
die Anwendung für die externe Domain und die Proxy-Header konfigurieren.
Beispiel:
[[proxies]]
name = "zimaos-service-two"
type = "tcp"
localIP = "192.168.1.50"
localPort = 3000
remotePort = 18081
Nginx würde die zweite Domain anschließend an folgenden lokalen Upstream weiterleiten:
http://127.0.0.1:18081
Auch dieser Port sollte ausschließlich auf 127.0.0.1 des VPS lauschen.
Unterschied zum normalen ZimaOS-Fernzugriff
ZimaOS bietet bereits eigene Funktionen für Fernzugriff, Verwaltung und privaten Zugriff.
Diese Architektur löst jedoch einen anderen Anwendungsfall:
-
Zugriff über eine normale öffentliche HTTPS-Domain
-
keine zusätzliche Clientsoftware für die Nextcloud-Benutzer
-
zentrale TLS-Terminierung auf einem VPS
-
mehrere öffentliche Dienste über denselben VPS
-
keine eingehende Portfreigabe am privaten Anschluss
-
keine direkte öffentliche Freigabe der privaten ZimaOS-Adresse
Der Aufbau ist deshalb vor allem dann sinnvoll, wenn eine Anwendung wie Nextcloud regulär über eine öffentliche Domain erreichbar sein soll, ohne das Heimnetz direkt für eingehende Verbindungen zu öffnen.
Weiterführende Dokumentation
Für die Umsetzung sind vor allem diese beiden offiziellen Dokumentationen relevant:
-
ZimaOS – Docker-Anwendungen anpassen:
https://www.zimaspace.com/docs/zimaos/docker-app-publishing -
Nextcloud – Reverse-Proxy-Konfiguration:
https://docs.nextcloud.com/server/stable/admin_manual/configuration_server/reverse_proxy_configuration.html