diff --git a/README.md b/README.md index bde001f..46fcdaf 100644 --- a/README.md +++ b/README.md @@ -220,43 +220,39 @@ Other operators can run their own [meshcore-packet-capture](https://github.com/a #### Example: Observer contributing to LetsMesh and your community Hub -```bash -# In the observer's .env or docker-compose environment: - -# Server 1 - Let's Mesh US (opt-in) -PACKETCAPTURE_MQTT1_ENABLED=true -PACKETCAPTURE_MQTT1_SERVER=mqtt-us-v1.letsmesh.net -PACKETCAPTURE_MQTT1_PORT=443 -PACKETCAPTURE_MQTT1_TRANSPORT=websockets -PACKETCAPTURE_MQTT1_USE_TLS=true -PACKETCAPTURE_MQTT1_USE_AUTH_TOKEN=true -PACKETCAPTURE_MQTT1_TOKEN_AUDIENCE=mqtt-us-v1.letsmesh.net - -# Server 2 - Let's Mesh EU (opt-in) -PACKETCAPTURE_MQTT2_ENABLED=false - -# Server 3 - Your MeshCore Hub -PACKETCAPTURE_MQTT3_ENABLED=true -PACKETCAPTURE_MQTT3_SERVER=mqtt.example.com -PACKETCAPTURE_MQTT3_PORT=443 -PACKETCAPTURE_MQTT3_TRANSPORT=websockets -PACKETCAPTURE_MQTT3_USE_TLS=true -PACKETCAPTURE_MQTT3_USE_AUTH_TOKEN=true -PACKETCAPTURE_MQTT3_TOKEN_AUDIENCE=mqtt.example.com -``` - -Replace `mqtt.example.com` with your public MQTT domain. The `TOKEN_AUDIENCE` must match the `MQTT_TOKEN_AUDIENCE` or `AUTH_EXPECTED_AUDIENCE` configured on your broker. - -For local network observers (no TLS): +A ready-made Docker Compose setup is provided in `contrib/packetcapture/`. Download it and configure: ```bash -PACKETCAPTURE_MQTT3_SERVER=192.168.1.100 -PACKETCAPTURE_MQTT3_PORT=1883 -PACKETCAPTURE_MQTT3_TRANSPORT=websockets -PACKETCAPTURE_MQTT3_USE_TLS=false -PACKETCAPTURE_MQTT3_TOKEN_AUDIENCE=mqtt.localhost +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: + +| Variable | Description | +|----------|-------------| +| `SERIAL_PORT` | Device path for your Meshtastic device (e.g. `/dev/ttyUSB0`, or `/dev/serial/by-id/...` for a stable path) | +| `IATA` | 3-letter area code for your location (e.g. `STN`, `SEA`) | +| `ORIGIN` | Observer identifier (default: `observer`) | +| `ENABLE_LETSMESH_US` | Set `true` to contribute to LetsMesh US | +| `ENABLE_LETSMESH_EU` | Set `true` to contribute to LetsMesh EU | +| `CUSTOM_MQTT_HOST` | Your community Hub's public MQTT domain (e.g. `mqtt.example.com`) | +| `CUSTOM_MQTT_PORT` | MQTT port — `443` for TLS/WSS, `1883` for local/plain | +| `CUSTOM_MQTT_TLS` | `true` for TLS, `false` for plain connections | +| `CUSTOM_MQTT_AUDIENCE` | Must match `MQTT_TOKEN_AUDIENCE` on your broker (e.g. `mqtt.example.com` for TLS, `mqtt.localhost` for local) | + +Then start the observer: + +```bash +docker compose up -d +``` + +> **Local network (no TLS):** Set `CUSTOM_MQTT_HOST` to the Hub's LAN IP (e.g. `192.168.1.100`), `CUSTOM_MQTT_PORT=1883`, `CUSTOM_MQTT_TLS=false`, and `CUSTOM_MQTT_AUDIENCE=mqtt.localhost`. + ### Backup & Restore #### Using Makefile diff --git a/contrib/packetcapture/.env.example b/contrib/packetcapture/.env.example new file mode 100644 index 0000000..2ba372b --- /dev/null +++ b/contrib/packetcapture/.env.example @@ -0,0 +1,69 @@ +# ========================================================================== +# MeshCore Packet Capture - Observer Configuration +# ========================================================================== +# Copy this file to .env and update the values below. +# +# This observer captures MeshCore mesh traffic from a serial device and +# forwards decoded packets to one or more MQTT brokers. By default it sends +# to your community Hub and optionally to the LetsMesh network (US/EU). +# +# Prerequisites: +# - A Meshtastic device connected via USB (or modify CONNECTION_TYPE for network) +# - Your community Hub's MQTT broker must be accessible (WSS with TLS recommended) +# +# Quick start: +# cp .env.example .env # then edit .env +# docker compose up -d +# ========================================================================== + +# --------------------------------------------------------------------------- +# Serial / Device +# --------------------------------------------------------------------------- +# Path to your Meshtastic device. Use /dev/serial/by-id/... for a stable path +# that survives reboots (avoids /dev/ttyUSB0 reordering). +# Find your device: ls /dev/serial/by-id/ +SERIAL_PORT=/dev/ttyUSB0 + +# --------------------------------------------------------------------------- +# Identity +# --------------------------------------------------------------------------- +# 3-letter IATA airport code for your area (e.g. STN, SEA, LAX, AMS). +# Used as a location tag in MQTT topic paths. +IATA=STN + +# Observer name/identifier. Appears in packet metadata. +ORIGIN=observer + +# --------------------------------------------------------------------------- +# Schedule +# --------------------------------------------------------------------------- +# Hours between self-advertisement broadcasts (default: 11). +ADVERT_INTERVAL_HOURS=11 + +# --------------------------------------------------------------------------- +# LetsMesh (optional) +# --------------------------------------------------------------------------- +# Contribute captured packets to the LetsMesh network. +# Enable one or both servers to share data for the public mesh map. +# See https://letsmesh.net for more info. +ENABLE_LETSMESH_US=false +ENABLE_LETSMESH_EU=true + +# --------------------------------------------------------------------------- +# Community Hub MQTT Broker (required) +# --------------------------------------------------------------------------- +# Your community MeshCore Hub's MQTT broker. Captured packets are sent here +# for your local network dashboard. +# +# TLS (production / reverse proxy): +CUSTOM_MQTT_HOST=mqtt.example.com +CUSTOM_MQTT_PORT=443 +CUSTOM_MQTT_TLS=true +# CUSTOM_MQTT_AUDIENCE must match the MQTT_TOKEN_AUDIENCE on your broker +CUSTOM_MQTT_AUDIENCE=mqtt.example.com + +# Local network (no TLS) — uncomment and adjust these instead: +# CUSTOM_MQTT_HOST=192.168.1.100 +# CUSTOM_MQTT_PORT=1883 +# CUSTOM_MQTT_TLS=false +# CUSTOM_MQTT_AUDIENCE=mqtt.localhost diff --git a/contrib/packetcapture/docker-compose.yml b/contrib/packetcapture/docker-compose.yml new file mode 100644 index 0000000..c905bbf --- /dev/null +++ b/contrib/packetcapture/docker-compose.yml @@ -0,0 +1,49 @@ +services: + meshcore-packet-capture: + image: ghcr.io/agessaman/meshcore-packet-capture:latest + container_name: meshcore-packet-capture + devices: + - ${SERIAL_PORT:-/dev/ttyUSB0} + group_add: + - dialout + volumes: + - data:/app/data + environment: + - PACKETCAPTURE_CONNECTION_TYPE=${CONNECTION_TYPE:-serial} + - PACKETCAPTURE_SERIAL_PORTS=${SERIAL_PORT:-/dev/ttyUSB0} + # MQTT Broker 1 - Let'sMesh Analyzer (US) + - PACKETCAPTURE_MQTT1_ENABLED=${ENABLE_LETSMESH_US:-false} + - PACKETCAPTURE_MQTT1_SERVER=mqtt-us-v1.letsmesh.net + - PACKETCAPTURE_MQTT1_PORT=443 + - PACKETCAPTURE_MQTT1_TRANSPORT=websockets + - PACKETCAPTURE_MQTT1_USE_TLS=true + - PACKETCAPTURE_MQTT1_USE_AUTH_TOKEN=true + - PACKETCAPTURE_MQTT1_TOKEN_AUDIENCE=mqtt-us-v1.letsmesh.net + - PACKETCAPTURE_MQTT1_KEEPALIVE=120 + # MQTT Broker 2 - Let'sMesh Analyzer (EU) + - PACKETCAPTURE_MQTT2_ENABLED=${ENABLE_LETSMESH_EU:-false} + - PACKETCAPTURE_MQTT2_SERVER=mqtt-eu-v1.letsmesh.net + - PACKETCAPTURE_MQTT2_PORT=443 + - PACKETCAPTURE_MQTT2_TRANSPORT=websockets + - PACKETCAPTURE_MQTT2_USE_TLS=true + - PACKETCAPTURE_MQTT2_USE_AUTH_TOKEN=true + - PACKETCAPTURE_MQTT2_TOKEN_AUDIENCE=mqtt-eu-v1.letsmesh.net + - PACKETCAPTURE_MQTT2_KEEPALIVE=120 + # IPNet MQTT Broker + - PACKETCAPTURE_MQTT3_ENABLED=true + - PACKETCAPTURE_MQTT3_SERVER=${CUSTOM_MQTT_HOST} + - PACKETCAPTURE_MQTT3_PORT=${CUSTOM_MQTT_PORT:-443} + - PACKETCAPTURE_MQTT3_TRANSPORT=websockets + - PACKETCAPTURE_MQTT3_USE_TLS=${CUSTOM_MQTT_TLS:-true} + - PACKETCAPTURE_MQTT3_USE_AUTH_TOKEN=true + - PACKETCAPTURE_MQTT3_TOKEN_AUDIENCE=${CUSTOM_MQTT_AUDIENCE} + - PACKETCAPTURE_MQTT3_KEEPALIVE=120 + # Area/Origin + - PACKETCAPTURE_IATA=${IATA} + - PACKETCAPTURE_ORIGIN=${ORIGIN:observer} + # Schedule/Timeouts + - PACKETCAPTURE_ADVERT_INTERVAL_HOURS=${ADVERT_INTERVAL_HOURS:-11} + restart: unless-stopped + +volumes: + data: