Remote Observers

July 4, 2026 · View on GitHub

Other operators can run their own meshcore-packet-capture instance and publish decoded packets to your MeshCore Hub. They can also optionally contribute to the LetsMesh and MeshRank networks.

This document covers the local packet-capture observer (the observer compose profile) and the remote-observer contribution flow. The PACKETCAPTURE_* and SERIAL_PORT variables that configure the external capture image are documented at the bottom of this page; for everything else see configuration.md.

Prerequisite: Your MQTT broker must be accessible to remote observers. In production, this means exposing the WebSocket listener via a reverse proxy with TLS (e.g., wss://mqtt.example.com/mqtt).

Restricting which observers are accepted: because anyone with broker access can publish as an observer, Hub operators can gate ingestion by observer public key using OBSERVER_ALLOWLIST / OBSERVER_DENYLIST. See configuration.md → Observer Ingestion Filters.

Example: Contribute to MeshCore Hub, MeshRank and other services

A ready-made Docker Compose setup is provided in contrib/packetcapture/. Download it and configure:

mkdir meshcore-observer && cd meshcore-observer

wget https://raw.githubusercontent.com/ipnet-mesh/meshcore-hub/main/contrib/packetcapture/docker-compose.yml
wget https://raw.githubusercontent.com/ipnet-mesh/meshcore-hub/main/contrib/packetcapture/.env.example

cp .env.example .env

Edit .env and update the following variables:

VariableDescription
SERIAL_PORTDevice path for your MeshCore companion device (e.g. /dev/ttyUSB0, or /dev/serial/by-id/... for a stable path)
IATA3-letter area code for your location (e.g. STN, SEA)
ORIGINObserver identifier (default: observer)
IPNET_ENABLESet true to contribute packets to IPNet MeshCore Hub (default: true)
MESHRANK_ENABLESet true to contribute to MeshRank (default: false)
MESHRANK_UPLINK_KEYYour MeshRank uplink key (required if MeshRank enabled)
CUSTOM_ENABLESet true to publish to a custom MQTT broker (default: false)
CUSTOM_MQTT_SERVERCustom MQTT broker hostname
CUSTOM_MQTT_PORTCustom MQTT broker port (default: 8883)
CUSTOM_MQTT_USE_TLStrue for TLS, false for plain (default: true)
CUSTOM_MQTT_USERNAMEUsername for custom broker auth
CUSTOM_MQTT_PASSWORDPassword for custom broker auth

Then start the observer:

docker compose up -d

Local network (no TLS): Set CUSTOM_MQTT_SERVER to the Hub's LAN IP (e.g. 192.168.1.100), CUSTOM_MQTT_PORT=1883, and CUSTOM_MQTT_USE_TLS=false.

Packet Capture Settings

The variables below configure the external meshcore-packet-capture image (ghcr.io/agessaman/meshcore-packet-capture), which is run by the observer compose profile. They are not consumed by MeshCore Hub itself — they are listed here because they live in the same .env and are needed by operators running an observer. See the meshcore-packet-capture documentation for full details.

Device

VariableDefaultDescription
SERIAL_PORT/dev/ttyUSB0Serial port for the packet-capture device (typically /dev/ttyUSB[0-9] or /dev/ttyACM[0-9] on Linux)
PACKETCAPTURE_IATALOC3-letter IATA airport/area code used in topic templates
PACKETCAPTURE_ORIGIN(device name)Observer display name (defaults to the device name from the MeshCore connection)
PACKETCAPTURE_IMAGE_VERSIONlatestDocker image tag for the packet-capture image

Connection behaviour

VariableDefaultDescription
PACKETCAPTURE_TIMEOUT30Connection timeout in seconds
PACKETCAPTURE_MAX_CONNECTION_RETRIES5Max device-connection retries
PACKETCAPTURE_CONNECTION_RETRY_DELAY5Seconds between device-connection retries
PACKETCAPTURE_HEALTH_CHECK_INTERVAL30Seconds between health checks
PACKETCAPTURE_ADVERT_INTERVAL_HOURS11Send flood adverts at this interval in hours (0 = disabled)
PACKETCAPTURE_RF_DATA_TIMEOUT15.0RF data cache timeout in seconds

MQTT reconnection

VariableDefaultDescription
PACKETCAPTURE_MAX_MQTT_RETRIES5Max MQTT reconnection attempts
PACKETCAPTURE_MQTT_RETRY_DELAY5Seconds between MQTT reconnection attempts
PACKETCAPTURE_EXIT_ON_RECONNECT_FAILtrueExit the process when MQTT reconnection fails