Marstek Offline Endpoint auf einem UGREEN-NAS einrichten
Den Marstek Offline Endpoint auf einem UGREEN-NAS mit der Docker-App betreiben. Per macvlan bekommt er eine eigene IP und kollidiert nicht mit der NAS-Oberfläche; per DNS spricht die Batterie dann ihn statt der Cloud an.
Der Marstek Offline Endpoint ist ein kleiner Container, der den Telemetrie-Upload eines Marstek Venus (E, D, E v3) im Heimnetz beantwortet. Ohne Antwort aus der Cloud setzt die Batterie auf der Control-Firmware v150 alle 30 Minuten ihren Netzwerkchip zurück; Modbus-Verbindungen brechen dabei ab. Firmware v151 startet stattdessen die Steuerung neu, wenn vier Stunden lang mindestens fünf Uploads unversendet bleiben, und schaltet dabei den Wechselrichterausgang ab. Der Container bestätigt jeden Upload, damit beides gar nicht erst eintritt.
So funktioniert die Umleitung
Die Batterie spricht zwei Server an: api-eu.marstekcloud.com für den Upload (HTTPS, Port 443) und eu.hamedata.com für die Uhrzeit (HTTP, Port 80). Du änderst nichts an der Batterie. Stattdessen sorgst du im Heimnetz dafür, dass beide Namen auf den Rechner zeigen, auf dem der Container läuft. Dazu legst du zwei DNS-Einträge für die ganzen Domains marstekcloud.com und hamedata.com an, damit auch eine andere Region als eu im Namen funktioniert. Die Ports 80 und 443 lassen sich nicht ändern, die Batterie verbindet sich fest dorthin.
Zwei Dinge gehören ausdrücklich nicht dazu: Den MQTT-Broker der Batterie leitest du nicht um (er prüft Zertifikate und lässt sich nicht nachbilden), und der Container gehört nicht ins Internet. Öffne also keine Ports im Router dorthin.
Warum der Container eine eigene IP-Adresse bekommt
Der Container braucht die Ports 80 und 443, und die Batterie verbindet sich fest dorthin. Auf einem UGREEN-NAS sind genau diese Ports in der Regel schon von der Weboberfläche des NAS belegt. Statt dort etwas umzubauen, bekommt der Container eine eigene Adresse im Heimnetz, so als wäre er ein weiteres Gerät. Die Ports 80 und 443 gehören dann ihm allein, ohne Konflikt mit dem NAS.
Technisch heißt das macvlan: Der Container hängt mit einer eigenen MAC-Adresse direkt im LAN. Diese Adresse ist auch das Ziel der späteren DNS-Einträge. Es gibt eine bekannte Einschränkung: Das NAS selbst kann den Container über diese Adresse nicht erreichen, alle anderen Geräte im Netz schon. Das stört hier nicht, denn die Batterie und dein PC sind andere Geräte. Nur Tests wie ping oder nslookup führst du von einem PC aus durch, nicht auf dem NAS.
Vorbereitung
Die Anleitung folgt der Beschreibung von UGREEN für UGOS Pro ab Firmware 1.19.1.0126. Ältere Versionen können abweichende Menüs haben, und je nach Version können Bezeichnungen leicht abweichen. Die Weboberfläche des NAS öffnest du im Browser oder im UGREEN-PC-Client.
Docker-App installieren
- Öffne das „App Center“.
- Suche nach „Docker“.
- Klicke bei der App „Docker“ auf „Installieren“ und folge dem Assistenten.
- Öffne danach das Symbol „Docker“.
UGREEN rät davon ab, die Docker-App auf ARM-basierten Geräten mit 4 GB RAM oder weniger zu installieren. Bei diesen Modellen ist der Betrieb weniger stabil.
Registry-Mirror, nur falls nötig
Die UGREEN-Anleitung nennt eine Registry-Mirror-Adresse als ersten Schritt. Sie hilft, wenn das Herunterladen von Images fehlschlägt oder sehr langsam ist. Probiere zuerst ohne Mirror. Erst bei Problemen trägst du unter „Image › Einstellungen › Image-Repository › Registrierungseinstellungen“ eine Adresse ein oder wählst einen vorgeschlagenen Mirror. Docker startet danach neu.
Netzwerkwerte sammeln
Für das Netzwerk in der Compose-Datei brauchst du vier Werte. Alle vier findest du in der Weboberfläche deines Routers, die ersten drei auch in den Netzwerkeinstellungen des NAS.
- Die Schnittstelle des NAS („parent“): der LAN-Anschluss, über den das NAS im Netz hängt, meist
eth0. Bei einem Zusammenschluss mehrerer Anschlüsse oder aktiviertem Open vSwitch heißt sie anders, etwabond0oderovs_eth0. Sie muss ein Kabelanschluss sein; über WLAN funktioniert macvlan in der Regel nicht. - Das Subnetz: Wenn die Adresse deines NAS mit
192.168.1.beginnt und die Subnetzmaske255.255.255.0lautet, ist das Subnetz192.168.1.0/24. Das/24steht für diese Maske. - Das Gateway: die Adresse deines Routers, meist
192.168.1.1. - Eine freie IP-Adresse für den Container, die der DHCP-Server deines Routers nicht vergibt. Schau im Router nach dem DHCP-Bereich (zum Beispiel 192.168.1.100 bis 192.168.1.200) und wähle eine Adresse außerhalb, zum Beispiel
192.168.1.60. Prüfe mitping 192.168.1.60von einem PC, dass niemand antwortet.
Im Folgenden gelten diese Beispielwerte: Schnittstelle eth0, Subnetz 192.168.1.0/24, Gateway 192.168.1.1, Container-Adresse 192.168.1.60. Ersetze sie in der Compose-Datei durch deine eigenen.
Projekt erstellen
Du legst den Container als Projekt an. Das ist eine Compose-Datei, die du direkt in die Oberfläche einfügst. Für die Daten verwendet die Datei Docker-Volumes, damit du keine Ordnerpfade des NAS eintragen musst. Die Messdaten liegen dann im Docker-Bereich und sind über die Dateien-App nicht sichtbar; das Protokoll des Containers reicht für die Kontrolle.
- Öffne in der Docker-App den Bereich „Projekt“.
- Klicke auf „Erstellen“.
- Trage bei „Projektname“ ein:
marstek-offline-endpoint. - Füge unter „Compose-Konfiguration“ den folgenden Inhalt ein und passe die mit ANPASSEN markierten Werte an dein Netz an.
# Marstek Offline Endpoint: beantwortet die Cloud-Anfragen deiner Marstek Venus im Heimnetz
services:
marstek-offline-endpoint:
image: ghcr.io/sphings79/marstek-offline-endpoint:latest # fertiges Image für PC, NAS und Raspberry Pi
container_name: marstek-offline-endpoint
restart: unless-stopped # startet nach einem Neustart automatisch wieder, das ist wichtig
networks:
meo_lan:
ipv4_address: 192.168.1.60 # ANPASSEN: freie Adresse für den Container, außerhalb des DHCP-Bereichs
# Keine "ports": Der Container hat eine eigene IP und lauscht dort direkt auf 80 und 443.
volumes:
- marstek-data:/data # empfangene Messdaten, eine Datei pro Tag
- marstek-certs:/certs # selbst erzeugtes Zertifikat, wird beim ersten Start angelegt
environment:
- TZ=Europe/Berlin # deine Zeitzone, sonst stellt der Container die Uhr der Batterie auf UTC
networks:
meo_lan:
driver: macvlan
driver_opts:
parent: eth0 # ANPASSEN: LAN-Anschluss des NAS (Kabel)
ipam:
config:
- subnet: 192.168.1.0/24 # ANPASSEN: dein Subnetz
gateway: 192.168.1.1 # ANPASSEN: dein Router
volumes:
marstek-data:
marstek-certs:
- Klicke auf „Bereitstellen“.
UGOS lädt das Image aus der GitHub Container Registry, legt das Netzwerk an und erstellt den Container. Das dauert eine Weile. Zum Schluss zeigt das Projekt einen laufenden Status.
Start prüfen
- Öffne in der Docker-App den Bereich „Container“.
- Der Container
marstek-offline-endpointmuss den Status „Läuft“ haben. - Klicke auf den Container, um die Details zu öffnen.
- Wähle „Protokoll“.
Du willst drei „listening“-Zeilen sehen und keine Fehler:
https listening on :443
http listening on :80
mqtt probe listening on :8883Der Container startet nach einem Neustart des NAS automatisch wieder, dafür sorgt restart: unless-stopped in der Compose-Datei, solange die Docker-App mit dem NAS startet.
DNS-Einträge anlegen
Jetzt kommt der Schritt, der die Batterie tatsächlich zu deinem Container umleitet. Du brauchst Zugriff auf den DNS-Server, den dein Heimnetz benutzt. Das ist meist ein Pi-hole oder AdGuard Home, manchmal der Router selbst, wenn er lokale DNS-Einträge für ganze Domains erlaubt. Als Ziel trägst du die feste Adresse des Containers ein; in dieser Anleitung ist das als Beispiel 192.168.1.60. Setze deine eigene Adresse ein.
So findest du heraus, wo du die Einträge anlegen musst: Schau in die DHCP-Einstellungen deines Routers. Der dort verteilte DNS-Server ist der, den auch die Batterie bekommt, und genau dort musst du die Einträge anlegen.
AdGuard Home
- Öffne die Weboberfläche von AdGuard Home.
- Wechsle zu „Filter › DNS-Umschreibungen“.
- Klicke auf „DNS-Umschreibung hinzufügen“.
- Trage als Domain
marstekcloud.comund als IP-Adresse192.168.1.60ein und speichere. - Lege ebenso
*.marstekcloud.commit192.168.1.60an. - Lege
hamedata.commit192.168.1.60an. - Lege
*.hamedata.commit192.168.1.60an.
AdGuard Home übernimmt Umschreibungen sofort. Es sind vier Einträge, jeweils die Domain ohne und mit Platzhalter.
Pi-hole
Die Maske für lokale DNS-Einträge in Pi-hole nimmt nur ganze Hostnamen. Einfacher ist eine kleine Konfigurationsdatei für den eingebauten dnsmasq-Dienst. Du legst sie auf dem Gerät an, auf dem Pi-hole läuft.
- Öffne ein Terminal auf dem Pi-hole-Rechner und gib den folgenden Befehl ein. Ersetze zuvor die Adresse durch deine eigene.
sudo tee /etc/dnsmasq.d/99-marstek.conf >/dev/null <<'EOF'
address=/marstekcloud.com/192.168.1.60
address=/hamedata.com/192.168.1.60
EOF- Starte den DNS-Dienst von Pi-hole neu.
pihole restartdnsWenn du statt der Domains nur die beiden genauen Namen eintragen willst, geht das in der Pi-hole-Oberfläche als lokaler DNS-Eintrag für api-eu.marstekcloud.com und für eu.hamedata.com. Das gilt dann nur für die Region eu, die bei der Batterie im Test beobachtet wurde. Die Domain-Variante ist die sicherere.
Router oder anderer DNS-Server
Wenn dein Router oder Firewall-System einen lokalen DNS-Eintrag oder „Host Override“ für eine ganze Domain anbietet, gelten dieselben zwei Domains mit derselben Zieladresse. Bei OPNsense liegt das unter „Services › Unbound DNS › Overrides › Domain Overrides“. Ob dein Router das kann, steht in dessen Handbuch; nicht jeder Router erlaubt Einträge für ganze Domains. Wenn nicht, brauchst du einen eigenen DNS-Server wie Pi-hole oder AdGuard Home.
Prüfen, ob die Einträge greifen
- Öffne auf einem PC oder Mac ein Terminal (unter Windows die Eingabeaufforderung oder PowerShell) und frage den ersten Namen ab.
nslookup api-eu.marstekcloud.com- Frage auch den zweiten Namen ab.
nslookup eu.hamedata.comIn beiden Antworten muss unter „Name“ der jeweilige Hostname stehen und unter „Address“ die Adresse 192.168.1.60, also deine Container-Adresse, keine öffentliche. Steht dort eine fremde Adresse, benutzt dein PC einen anderen DNS-Server. Frage dann den richtigen direkt ab, indem du dessen Adresse anhängst: nslookup api-eu.marstekcloud.com DNS-SERVER-IP.
Die Batterie muss denselben DNS-Server benutzen wie dieser Test. Manche Geräte ignorieren den per DHCP verteilten DNS-Server und benutzen einen fest eingebauten. Dann hilft statt DNS eine Firewall-Regel (DNAT) im Router: Verkehr von der IP der Batterie auf die Ports 443 und 80 wird auf den Container umgebogen. Wenn die Batterie in einem eigenen VLAN hängt, muss sie den Container außerdem erreichen dürfen.
Kontrolle
- Öffne in der Docker-App „Container“.
- Klicke auf
marstek-offline-endpointund wähle „Protokoll“.
Innerhalb von etwa fünf Minuten erscheinen Zeilen wie diese (Uhrzeit und Anhänge sind bei dir anders):
2026-08-26 08:17:38 TIME http GET eu.hamedata.com/app/neng/getDateInfoeu.php?uid=… (0 B)
2026-08-26 08:19:07 ACCEPT https POST api-eu.marstekcloud.com/data-upload/v1/venus/… (1204 B)TIME ist die Batterie, die nach der Uhrzeit fragt. ACCEPT ist der Telemetrie-Upload, den der Container bestätigt. Beides zusammen heißt: Die Umleitung funktioniert. Die Zeitabfrage kommt etwa alle zehn Minuten, der Upload etwa alle fünf Minuten.
Kommen vier TIME-Zeilen im Abstand von 20 Sekunden hintereinander, lehnt die Batterie die Antwort ab; dann läuft ein veraltetes Image, lade es neu. Kommen Uploads exakt alle 86 Sekunden, ist noch ein Rückstau in der Batterie abzubauen. Das ist für ein bis zwei Stunden normal.
Um zu sehen, dass die Abbrüche weg sind, kannst du von einem Mac oder Linux-Rechner, der durchläuft, die Batterie anpingen. Das folgende Skript meldet sich nur, wenn ein Ping ausfällt; so sieht ein Netzwerk-Reset der Batterie von außen aus. Ersetze 192.168.1.50 durch die IP deiner Batterie (in der Geräteliste deines Routers, meist als „Marstek“, „VenusE“ oder ähnlich geführt).
IP=192.168.1.50; F=0
while true; do
if ping -c1 -W1 "$IP" >/dev/null 2>&1; then
[ $F -gt 0 ] && echo "$(date '+%F %T') WIEDER DA nach ${F}s"; F=0
else
[ $F -eq 0 ] && echo "$(date '+%F %T') WEG"; F=$((F+1))
fi
sleep 1
doneBleibt die Ausgabe über zwei halbe Stunden leer, ist es geschafft. Vorher stand dort alle 30 Minuten eine Meldung. Beim gemessenen Gerät dauerte es nach dem ersten bestätigten Upload etwa 45 Minuten, bis der Rückstau abgebaut war und die Abbrüche aufhörten.
Ein Rest bleibt, den der Container nicht beheben kann: Bei jedem Upload rechnet die Batterie etwa vier bis fünf Sekunden am TLS-Schlüsselaustausch und beantwortet in der Zeit kein Modbus. Stelle deshalb in deinem Modbus-Client ein Antwort-Timeout von mindestens 6 Sekunden ein.
Wenn etwas nicht klappt
Nach 15 Minuten steht nichts im Log.
Die Batterie landet nicht beim Container. Wiederhole die nslookup-Prüfung. Sieht sie richtig aus, hat die Batterie womöglich eine alte Antwort zwischengespeichert: Trenne sie kurz vom Strom, schalte sie wieder ein und warte fünf Minuten. Kommt immer noch nichts, benutzt sie einen fest eingebauten DNS-Server, dann hilft die DNAT-Regel im Router.
TIME-Zeilen kommen, aber kein ACCEPT.
Nur hamedata.com ist umgeleitet, marstekcloud.com nicht. Prüfe den zweiten DNS-Eintrag samt Platzhalter-Variante.
Das Projekt startet nicht, es gibt eine Meldung zum Netzwerk.
Meistens stimmt einer der Werte im Netzwerkteil nicht: Subnetz, Gateway oder Schnittstelle. Prüfe sie noch einmal gegen deinen Router und die Netzwerkeinstellungen des NAS. Ist die gewählte Container-Adresse bereits vergeben oder liegt sie nicht im Subnetz, scheitert das Starten ebenfalls.
Der Container antwortet nicht auf ping.
Teste von einem anderen Gerät, nicht vom NAS aus: Der Zugriff vom NAS auf den eigenen Container ist bei macvlan nicht möglich. Antwortet auch der PC nicht, läuft der Container nicht oder die Schnittstelle (parent) stimmt nicht. Bei einem WLAN-Anschluss funktioniert macvlan meistens nicht. In seltenen Fällen lässt ein Switch oder Router mit Port-Sicherheit nur eine MAC-Adresse pro Anschluss zu.
Eine andere Adresse im Netz ist plötzlich nicht mehr erreichbar.
Die Container-Adresse wird noch von einem anderen Gerät benutzt (Adresskonflikt). Wähle eine andere freie Adresse, ändere sie in der Compose-Datei und stelle das Projekt neu bereit.
Das Image lässt sich nicht herunterladen.
Das Image liegt bei ghcr.io (GitHub Container Registry). Prüfe, dass das NAS ins Internet kommt. Hilft das nicht, trage wie oben beschrieben einen Registry-Mirror ein.
Ich sehe die Messdaten nicht in der Dateien-App.
Das ist gewollt: Die Compose-Datei benutzt Docker-Volumes statt NAS-Ordnern. Für die Kontrolle genügt das Protokoll des Containers.
Andere Systeme
Unterstützen
Diese Tools entstehen in meiner Freizeit und bleiben kostenlos, offen und cloud-frei. Wenn dir eins davon einen Nachmittag gespart hat, freue ich mich über einen Kaffee oder ein Stück Pizza.
Kaffee oder Pizza