mirror of
https://github.com/ruvnet/RuView.git
synced 2026-10-18 21:00:22 -05:00
Since ADR-296 the sensing server binds its UDP receiver to 127.0.0.1 by default, and docker-entrypoint.sh never set a UDP bind. Inside a container that address cannot receive from the published 5005/udp port, so the default image never shows a node (#2089, follow-up to #1394). The entrypoint now binds UDP on 0.0.0.0 only when the operator has set an ADR-296 source guard (RUVIEW_UDP_ALLOW, RUVIEW_UDP_INSECURE_LAN, or the matching CLI flags). Without a guard it keeps the loopback bind and prints a note explaining why no node will appear and what to set, including the macOS bridge-gateway allowlist. An explicit RUVIEW_UDP_BIND or --udp-bind still wins. I chose this over defaulting the bind to 0.0.0.0 unconditionally. With no guard that would make the server refuse to start (exit 1) in auto mode, which binds UDP, and the guard would still have to be supplied. The change keeps ADR-296's fail-closed rule as is: a routable bind never happens without an allowlist or the explicit insecure opt-in. Auth defaults are unchanged. The entrypoint also normalizes RUVIEW_UDP_INSECURE_LAN=1/yes/on to true, since clap rejects 1 for that flag. The compose service passes RUVIEW_API_TOKEN, the RUVIEW_UDP_* variables and SENSING_ALLOWED_HOSTS through from the shell, with notes on the exit-64 auth check, the macOS gateway allowlist and the 421 Host check. The README and user-guide Docker quickstarts now set a token, and the user guide gains a "Receiving ESP32 frames in Docker" section. Co-Authored-By: claude-flow <ruv@ruv.net>
106 lines
4.3 KiB
YAML
106 lines
4.3 KiB
YAML
services:
|
|
sensing-server:
|
|
build:
|
|
context: ..
|
|
dockerfile: docker/Dockerfile.rust
|
|
image: ruvnet/wifi-densepose:latest
|
|
# ESP32 CSI must accept LAN UDP; TCP APIs below remain loopback-only.
|
|
# kics-scan ignore-line
|
|
ports:
|
|
- "127.0.0.1:3000:3000" # REST API
|
|
- "127.0.0.1:3001:3001" # WebSocket
|
|
# ESP32 UDP. On Linux/macOS this works with multiple ESP32 nodes out of
|
|
# the box. On Docker Desktop for Windows, multi-source UDP is collapsed
|
|
# to one source IP at the WSL/Hyper-V boundary, so all-but-one node's
|
|
# frames are silently dropped (issue #374, #386).
|
|
#
|
|
# Windows workaround: change this to "5006:5005/udp" and run the host
|
|
# relay so every datagram arrives from the same loopback source:
|
|
#
|
|
# python scripts/udp-relay.py --listen-port 5005 --forward-port 5006
|
|
#
|
|
# See docs/TROUBLESHOOTING.md §9 for details.
|
|
- "5005:5005/udp"
|
|
environment:
|
|
- RUST_LOG=info
|
|
# CSI_SOURCE controls the data source for the sensing server.
|
|
# Options: auto (default) — probe for ESP32 UDP then host WiFi; **fail
|
|
# hard with exit 78 if neither is detected**.
|
|
# Synthetic data is no longer a silent fallback
|
|
# (issue #937 fix) — operators must opt in.
|
|
# esp32 — receive real CSI frames from an ESP32 on UDP port 5005
|
|
# wifi — use host Wi-Fi RSSI/scan data (Windows netsh)
|
|
# simulated — explicitly generate synthetic CSI for demo mode
|
|
- CSI_SOURCE=${CSI_SOURCE:-auto}
|
|
# MODELS_DIR controls where the server scans for .rvf model files.
|
|
# Mount a host directory and set this to make models visible:
|
|
# volumes: ["/path/to/models:/app/models"]
|
|
# MODELS_DIR=/app/models
|
|
- MODELS_DIR=${MODELS_DIR:-data/models}
|
|
# Auth (issue #864). The entrypoint refuses to start (exit 64) unless
|
|
# RUVIEW_API_TOKEN is set. Export it before `docker compose up`:
|
|
# export RUVIEW_API_TOKEN=$(openssl rand -hex 32)
|
|
# Bare names pass the host value through only when it is set.
|
|
- RUVIEW_API_TOKEN
|
|
# ESP32 UDP ingest (ADR-296, issue #2089). The UDP receiver defaults to
|
|
# 127.0.0.1, which cannot receive from the published 5005/udp port.
|
|
# Set ONE source guard and the entrypoint binds 0.0.0.0:
|
|
# RUVIEW_UDP_ALLOW=<node-ip-or-cidr> restrict sources (preferred)
|
|
# RUVIEW_UDP_INSECURE_LAN=true accept the spoofing risk
|
|
# Docker Desktop and OrbStack on macOS rewrite the source address to the
|
|
# bridge gateway, so a LAN-subnet allowlist drops every frame. There,
|
|
# allow the gateway instead:
|
|
# docker network inspect <project>_default \
|
|
# --format '{{(index .IPAM.Config 0).Gateway}}'
|
|
# RUVIEW_UDP_ALLOW=<gateway>/32
|
|
# The gateway admits anything that reaches the published port, so keep
|
|
# 5005/udp off untrusted networks.
|
|
- RUVIEW_UDP_ALLOW
|
|
- RUVIEW_UDP_INSECURE_LAN
|
|
- RUVIEW_UDP_BIND
|
|
# Browsing the UI from another machine also needs the host name or IP
|
|
# in SENSING_ALLOWED_HOSTS (otherwise 421), and the TCP ports above
|
|
# published beyond 127.0.0.1.
|
|
- SENSING_ALLOWED_HOSTS
|
|
security_opt:
|
|
- no-new-privileges:true
|
|
cap_drop:
|
|
- ALL
|
|
deploy:
|
|
resources:
|
|
limits:
|
|
cpus: "2.0"
|
|
memory: 1G
|
|
healthcheck:
|
|
test: ["CMD-SHELL", "kill -0 1"]
|
|
interval: 30s
|
|
timeout: 3s
|
|
retries: 3
|
|
# No explicit command needed — docker-entrypoint.sh uses CSI_SOURCE.
|
|
# Override with: command: ["--source", "esp32", "--tick-ms", "500"]
|
|
|
|
python-sensing:
|
|
build:
|
|
context: ..
|
|
dockerfile: docker/Dockerfile.python
|
|
image: ruvnet/wifi-densepose:python
|
|
ports:
|
|
- "127.0.0.1:8765:8765" # WebSocket
|
|
- "127.0.0.1:8080:8080" # UI
|
|
environment:
|
|
- PYTHONUNBUFFERED=1
|
|
security_opt:
|
|
- no-new-privileges:true
|
|
cap_drop:
|
|
- ALL
|
|
deploy:
|
|
resources:
|
|
limits:
|
|
cpus: "1.0"
|
|
memory: 512M
|
|
healthcheck:
|
|
test: ["CMD", "python", "-c", "import socket; socket.create_connection(('127.0.0.1', 8765), 2).close()"]
|
|
interval: 30s
|
|
timeout: 3s
|
|
retries: 3
|