Meshseer is a web view of a Meshtastic receiver's LongFast traffic. It shows what one receiver has heard on the primary channel: node map, broadcast chat, recent packets, and passive route data.
Try it:
- Live site: https://meshseer.nemexix.com/
- Container image:
ghcr.io/juanmhuerta/meshseer
- receiver perspective only; this is not an authoritative whole-mesh view
- primary channel only
- Meshtastic TCP interface only today
- public UI is read-only
- auto-traceroute is optional, local-only, and disabled by default
- frontend assets are vendored locally; the default basemap tiles still come from CARTO/OpenStreetMap
Requirements:
- Docker with Compose support
- a Meshtastic node reachable over TCP, usually on port
4403
- Copy the environment template:
cp .env.example .env- Edit
.envand set at least:
MESHSEER_MESHTASTIC_HOST=192.168.1.50
MESHSEER_MESHTASTIC_PORT=4403
MESHSEER_ENV=production- Pull the published image:
docker pull ghcr.io/juanmhuerta/meshseer:latest- Start Meshseer:
docker run --name meshseer \
--env-file .env \
-e MESHSEER_BIND_HOST=0.0.0.0 \
-e MESHSEER_BIND_PORT=8000 \
-e MESHSEER_DB_PATH=/data/meshseer.db \
-p 127.0.0.1:8000:8000 \
-v meshseer-data:/data \
--restart unless-stopped \
-d ghcr.io/juanmhuerta/meshseer:latest-
Open
http://127.0.0.1:8000/ -
Optional sanity check:
curl http://127.0.0.1:8000/api/statusNotes:
- The container stores SQLite data in the Docker volume
meshseer-data. - The container listens on
0.0.0.0:8000internally and is published on127.0.0.1:8000by default. - If you want local-only admin routes, also set
MESHSEER_ADMIN_BEARER_TOKENin.env. - Docker support currently assumes Meshtastic TCP. USB serial passthrough and BLE are not implemented.
- If you prefer Compose, use the included
compose.yamlas a starting point or replace the localbuild:step withimage: ghcr.io/juanmhuerta/meshseer:latest.
Requirements:
uv- Python
3.13if you are managing the interpreter yourself
Setup and run:
uv sync
cp .env.example .env
./start.shstart.sh loads .env if present, creates the database directory if needed, and runs a small preflight check before starting Uvicorn.
For trusted LAN testing on a development machine, set:
MESHSEER_BIND_HOST=0.0.0.0
MESHSEER_BIND_PORT=8000
MESHSEER_ENV=developmentFor production, leave MESHSEER_BIND_HOST unset or set it explicitly to 127.0.0.1.
Use .env.example as the baseline. The most important settings are:
MESHSEER_MESHTASTIC_HOST: Meshtastic TCP hostname or IP. Defaults tolocalhost.MESHSEER_MESHTASTIC_PORT: Meshtastic TCP port. Defaults to4403.MESHSEER_DB_PATH: SQLite database path. Defaults to./data/meshseer.dbwhen running locally.MESHSEER_LOCAL_NODE_NUM: optional override for the receiver node number shown in the UI and API.MESHSEER_ENV:developmentorproduction. Production disables/docs,/redoc, and/openapi.json.MESHSEER_BIND_HOST,MESHSEER_BIND_PORT: HTTP bind settings.MESHSEER_ADMIN_BEARER_TOKEN: enables the local-only admin API.
Additional supported settings:
- websocket tuning:
MESHSEER_WS_MAX_CONNECTIONS,MESHSEER_WS_QUEUE_SIZE,MESHSEER_WS_SEND_TIMEOUT_SECONDS,MESHSEER_WS_PING_INTERVAL_SECONDS,MESHSEER_WS_PING_TIMEOUT_SECONDS - retention and pruning:
MESHSEER_RETENTION_PACKETS_DAYS,MESHSEER_RETENTION_NODE_METRIC_HISTORY_DAYS,MESHSEER_RETENTION_TRACEROUTE_ATTEMPTS_DAYS,MESHSEER_RETENTION_PRUNE_INTERVAL_SECONDS - autotrace:
MESHSEER_AUTOTRACE_ENABLED,MESHSEER_AUTOTRACE_INTERVAL_SECONDS,MESHSEER_AUTOTRACE_TARGET_WINDOW_HOURS,MESHSEER_AUTOTRACE_COOLDOWN_HOURS,MESHSEER_AUTOTRACE_ACK_ONLY_COOLDOWN_HOURS,MESHSEER_AUTOTRACE_RESPONSE_TIMEOUT_SECONDS
Meshseer persists:
- primary-channel packets received by the connected receiver
- the latest known state for each heard node
- passive route information derived from observed
TRACEROUTE_APPand route-reply packets - traceroute attempt records if auto-traceroute is enabled
The route overlay only appears when Meshseer has an ordered hop list to draw. ACK-only or error responses do not create a visible path.
If you want to inspect the UI without live radio hardware:
- Install the dev environment:
uv sync --extra dev- Install Chromium for Playwright once:
uv run --extra dev playwright install chromium- Start the seeded demo app:
uv run meshseer-demo --port 8765- Capture screenshots:
uv run --extra dev python scripts/headless_capture.py --url http://127.0.0.1:8765/This writes screenshots to artifacts/headless/.
Auto-traceroute is the only intentionally active backend feature. It remains disabled by default and is meant for protected, local-only use.
When enabled, Meshseer:
- sends at most one traceroute per configured interval
- targets recent RF nodes only
- skips the local node, MQTT nodes, and nodes without
hops_away - applies cooldowns after attempts, including failed ones
- records each attempt in SQLite with timestamps, hop limit, status, and packet IDs when available
Default values:
MESHSEER_AUTOTRACE_ENABLED=falseMESHSEER_AUTOTRACE_INTERVAL_SECONDS=300MESHSEER_AUTOTRACE_TARGET_WINDOW_HOURS=24MESHSEER_AUTOTRACE_COOLDOWN_HOURS=24MESHSEER_AUTOTRACE_ACK_ONLY_COOLDOWN_HOURS=6MESHSEER_AUTOTRACE_RESPONSE_TIMEOUT_SECONDS=20
The admin API is mounted only when MESHSEER_ADMIN_BEARER_TOKEN is configured.
Admin endpoints:
GET /api/admin/healthGET /api/admin/mesh/autotracePOST /api/admin/mesh/autotrace/enablePOST /api/admin/mesh/autotrace/disableGET /api/admin/mesh/linksGET /api/admin/nodesGET /api/admin/packets/{packet_id}
Example:
export MESHSEER_ADMIN_BEARER_TOKEN='replace-me'
curl -H "Authorization: Bearer ${MESHSEER_ADMIN_BEARER_TOKEN}" http://127.0.0.1:8000/api/admin/mesh/autotraceAttempt statuses:
success: a route-bearing reply was receivedack_only: a routing ACK was received without route datano_route: the radio replied with a routing error such asNO_ROUTEtimeout: no response arrived before the timeouterror: the send path or response decoding failed unexpectedly
ack_only still counts as an attempt, but it does not produce a route line on the map.
- Keep the app bound to loopback in production.
/ws/eventsaccepts same-origin browser connections only.- Admin routes are intended to stay local-only behind
MESHSEER_ADMIN_BEARER_TOKEN. - The public dashboard uses
/api/status;/api/healthis primarily for local health checks.
Deployment notes for the public dashboard plus local-only admin topology live in deployment.md.
For a concrete Proxmox LXC plus Cloudflare Tunnel rollout, see deploy/proxmox/README.md.
Meshseer is licensed under GPL-3.0-only. See LICENSE.
Third-party asset notices and included upstream license texts live in THIRD_PARTY_NOTICES.md.
