Reverse Proxy
June 16, 2026 · View on GitHub
Reverse proxy support is mainly useful when public or LAN clients reach the stack on different ports than the backend listeners, or when you already run a proxy (Caddy, Traefik, nginx) that owns your TLS certificates. I do not use a reverse proxy for my own setup, so please report any issues.
Whatever endpoint a vacuum or the Roborock app connects to must present a valid, trusted TLS certificate — vacuums refuse to connect otherwise. That endpoint can be the server itself or the proxy in front of it; the rest of this page is about choosing which one terminates TLS.
Advertised Ports
Use these when the proxy maps public ports to different backend listener ports. The server binds the *_port listeners but advertises the advertised_* ports to the Roborock app, vacuums, and Home Assistant.
[network]
stack_fqdn = "api-roborock.example.com"
bind_host = "0.0.0.0"
# Backend listener ports.
https_port = 555
mqtt_tls_port = 8881
# Public ports advertised to clients.
advertised_https_port = 443
advertised_mqtt_tls_port = 8883
With that config the server listens on *:555 / *:8881, but responses advertise:
https://api-roborock.example.comssl://api-roborock.example.com:8883
TLS Termination Modes
local_tls (default) — the server terminates TLS
The server runs its own TLS listeners; the proxy forwards encrypted traffic to them. The proxy must preserve the original Host header. For MQTT, use a TCP/stream proxy (a normal HTTP location is not enough because MQTT is not HTTP).
If you already manage certificates in the proxy, point the server at the same certificate chain so both present an identical, valid cert:
[network]
listener_mode = "local_tls"
[tls]
mode = "provided"
cert_file = "/path/to/proxy/fullchain.pem"
key_file = "/path/to/proxy/privkey.pem"
external_tls — the proxy terminates TLS
The proxy terminates TLS and forwards plain HTTP/TCP to the server, which holds no certificates at all. The proxy is responsible for presenting a valid cert to clients.
[network]
listener_mode = "external_tls"
[tls]
# No certificate material is required in this mode.
mode = "provided"
Requirements:
- HTTPS: the proxy terminates TLS, preserves the original
Hostheader, and forwards plain HTTP tohttps_port. - MQTT: a stream / layer-4 proxy must terminate TLS with a valid cert on the public MQTT port and forward plain TCP to
mqtt_tls_port. An HTTP reverse proxy alone cannot do this. tls.modemust be"provided".external_tlsnever issues or renews certificates, socloudflare_acmeis rejected to avoid a silent no-op.
Do not expose the backend ports publicly. In
external_tlsthe server speaks plain, unencrypted HTTP and MQTT onhttps_port/mqtt_tls_port. Bind them to localhost or an internal Docker network reachable only by the proxy — never publish them to the host or the internet. With the bundledcompose.yaml, theports:mappings publish the backend ports; remove or restrict them so only the proxy reaches the server. If you run the proxy in the same Compose project, drop theports:entries entirely and reference the service by name (e.g.roborock-local-server:555).The Docker healthcheck defaults to
https. Inexternal_tlssetROBOROCK_SERVER_HEALTHCHECK_SCHEME=httpso it probes the plain-HTTP listener.
Example Caddy config (HTTPS via the standard reverse proxy, MQTT via the layer4 plugin):
api-roborock.example.com {
reverse_proxy roborock-local-server:555
}
# layer4 app (Caddy JSON / global block) terminating MQTT TLS on 8883
:8883 {
route {
tls
proxy {
upstream roborock-local-server:8881
}
}
}
What Is Not Supported
Path-prefix hosting is not supported. The Roborock protocol and the admin API expect the stack at the hostname root, for example /region, /api/..., and /admin.
external_tls is intended for Docker / standalone deployments. The Home Assistant add-on always terminates its own TLS and does not expose this option.