A comprehensive web application for monitoring off-grid mesh networks β Meshtastic, MeshCore, and MQTT β from a single dashboard. Built with React, TypeScript, and Node.js, featuring a beautiful Catppuccin Mocha dark theme and multi-database support (SQLite, PostgreSQL, MySQL).
For complete documentation, visit meshmonitor.org
- Getting Started Guide - Installation and quick start
- FAQ - Frequently asked questions and troubleshooting
- Configuration - Detailed configuration options
- Development - Contributing and development setup
Get MeshMonitor running in 60 seconds:
# 1. Create docker-compose.yml
cat > docker-compose.yml << 'EOF'
services:
meshmonitor:
image: ghcr.io/yeraze/meshmonitor:latest
ports:
- "8080:3001"
volumes:
- meshmonitor-data:/data
environment:
- MESHTASTIC_NODE_IP=192.168.1.100 # Seeds the first source on first boot; manage more from Dashboard β Sources
restart: unless-stopped
volumes:
meshmonitor-data:
EOF
# 2. Start MeshMonitor
docker compose up -d
# 3. Open http://localhost:8080Default login: admin / changeme (change after first login!)
For detailed installation instructions, configuration options, and deployment scenarios, see the Getting Started Guide.
Running on Kubernetes? MeshMonitor ships a Helm chart under helm/meshmonitor/:
# Minimal custom-values.yaml
cat > custom-values.yaml << 'EOF'
env:
meshtasticNodeIp: "192.168.1.100"
meshtasticUseTls: "false"
EOF
helm install meshmonitor ./helm/meshmonitor -f custom-values.yamlSee the Helm Chart README for ingress, TLS, persistence, and the full values reference, or the Helm Deployment Guide on the docs site.
MeshMonitor supports authentication via reverse proxy headers for seamless single sign-on (SSO) integration with Cloudflare Access, oauth2-proxy, Authelia, Traefik ForwardAuth, and similar solutions.
- Cloudflare Access - JWT-based authentication with custom role claims
- oauth2-proxy - Standard OAuth2 proxy with email/groups headers
- Generic proxies - Configurable header-based authentication
services:
meshmonitor:
image: ghcr.io/yeraze/meshmonitor:latest
environment:
# Enable proxy authentication
- PROXY_AUTH_ENABLED=true
- PROXY_AUTH_AUTO_PROVISION=true
# Admin detection
- PROXY_AUTH_ADMIN_GROUPS=admins,mesh-admins
- PROXY_AUTH_ADMIN_EMAILS=admin@example.com
# Required: Trust the reverse proxy
- TRUST_PROXY=1
# Optional: Logout redirect
- PROXY_AUTH_LOGOUT_URL=https://auth.example.com/oauth2/sign_out- MeshMonitor is NOT directly accessible (use Docker networks, firewall rules, or VPN)
TRUST_PROXYis configured to trust your reverse proxy- Your proxy validates authentication before forwarding requests
# Core settings
PROXY_AUTH_ENABLED=false # Enable proxy auth (default: false)
PROXY_AUTH_AUTO_PROVISION=false # Auto-create users (default: false)
# Admin detection (at least one recommended)
PROXY_AUTH_ADMIN_GROUPS= # Comma-separated admin groups (case-insensitive match)
PROXY_AUTH_ADMIN_EMAILS= # Comma-separated admin emails (case-insensitive match)
# Normal-user group gate (optional, see below)
PROXY_AUTH_NORMAL_USER_GROUPS= # Comma-separated groups allowed to access (empty = all allowed)
# JWT configuration (for Cloudflare Access)
PROXY_AUTH_JWT_GROUPS_CLAIM=groups # Groups claim path (supports Auth0 custom namespaces)
# Custom headers (optional, for non-standard proxies)
PROXY_AUTH_HEADER_EMAIL= # Custom email header name
PROXY_AUTH_HEADER_GROUPS= # Custom groups header name
# Logout
PROXY_AUTH_LOGOUT_URL= # Redirect URL after logout
# Audit logging
PROXY_AUTH_AUDIT_LOGGING=true # Log auth events (default: true)Cloudflare Access application JWTs contain a subset of the full identity β typically email, aud, iss, sub. Custom OIDC claims (e.g. Auth0 role claims) are only present when the IdP integration is configured to include them. If your PROXY_AUTH_JWT_GROUPS_CLAIM (e.g. https://your-domain/roles) is missing from the Cf-Access-Jwt-Assertion header, MeshMonitor will see empty groups and group-based admin will never trigger.
To verify: Decode a real request JWT at jwt.io using the Cf-Access-Jwt-Assertion header from browser DevTools, and confirm the groups claim exists and its shape. Cloudflare often places IdP custom claims under a custom object (e.g. custom["https://your-domain/roles"]); official examples may show a flatter layout β your decoded token is the ground truth for your tenant.
Fallback: Set PROXY_AUTH_ADMIN_EMAILS to an operator email allowlist. MeshMonitor matches emails case-insensitively, so admin works even when the app JWT omits custom IdP claims.
See: Cloudflare Application Token
MeshMonitor normalizes groups claims from the JWT to handle different IdP formats:
- String arrays (
["admin", "user"]) β used as-is - Single strings (
"admin") β wrapped into an array - Role objects (
[{ "name": "admin" }, { "name": "user" }]) β.nameis extracted
This handles Auth0 Post-Login Actions that emit role objects instead of plain strings. All group matching (admin groups, normal-user groups) is case-insensitive.
PROXY_AUTH_NORMAL_USER_GROUPS adds an application-layer group check as a second gate, on top of the reverse proxy's URL-level access control.
Two-layer model:
When configured, only users whose groups contain at least one value from this list (or who are admins) are allowed. Users who passed the proxy but lack a matching group receive 403 FORBIDDEN_PROXY_GROUP.
When empty (default), all proxy-authenticated users are allowed β the reverse proxy is the only gate.
Cloudflare Access + Auth0 (with normal-user gate):
PROXY_AUTH_ENABLED=true
PROXY_AUTH_AUTO_PROVISION=true
PROXY_AUTH_JWT_GROUPS_CLAIM=https://mydomain.com/roles
PROXY_AUTH_ADMIN_GROUPS=admins
PROXY_AUTH_NORMAL_USER_GROUPS=meshmonitor-users
PROXY_AUTH_ADMIN_EMAILS=operator@example.com
PROXY_AUTH_LOGOUT_URL=https://yourteam.cloudflareaccess.com/cdn-cgi/access/logout
TRUST_PROXY=1
COOKIE_SECURE=trueoauth2-proxy:
PROXY_AUTH_ENABLED=true
PROXY_AUTH_AUTO_PROVISION=true
PROXY_AUTH_ADMIN_EMAILS=admin@example.com,superuser@example.com
PROXY_AUTH_LOGOUT_URL=https://auth.example.com/oauth2/sign_out
TRUST_PROXY=1When proxy authentication is enabled, existing local users are automatically migrated on first login if their email matches:
authMethodupdated to'proxy'- Password cleared (same behavior as OIDC migration)
- Admin status updated based on groups
MeshMonitor supports multiple deployment methods:
-
π³ Docker (Recommended) - Pre-built multi-architecture images with auto-upgrade support
- Docker Compose Guide
- Platforms: amd64, arm64, armv7
-
βΈοΈ Kubernetes / Helm - Helm chart for production clusters
- Helm Chart README β full install, values, ingress, and TLS reference
- Helm Deployment Guide β quick-start on the docs site
- GitOps-ready with ArgoCD/Flux support
-
π¦ Proxmox LXC - Lightweight containers for Proxmox VE
- Proxmox LXC Guide
- Pre-built templates available
- Community-supported alternative
-
π§ Manual - Direct Node.js deployment (bare metal)
- Bare Metal (Node.js) Deployment Guide
- For development or custom setups
- Note: the SQLite default path is
/data/meshmonitor.db(Docker convention). Bare-metal installs must setDATABASE_PATHto a writable location or create/data/for the runtime user.
-
π₯οΈ Desktop Apps - Native applications for Windows and macOS
- Download from GitHub Releases
- Runs as a system tray application
- Windows (.exe) and macOS (.dmg) installers available
- Multi-Protocol, Multi-Source - Monitor Meshtastic (TCP/Serial/BLE), MeshCore (USB/TCP), and MQTT brokers from a single deployment, with per-source permissions, schedulers, and Virtual Nodes
- Embedded MQTT Broker - Optional built-in broker with bidirectional bridges to public upstreams and topic/channel/portnum/geo filtering
- Analysis & Reports (4.2) - Cross-source analytical workspace at
/reports; first report is Solar Monitoring Analysis with auto-detection of solar-powered nodes, production overlay, healthy-level reference lines, and multi-day battery forecast simulation - Real-time Mesh Monitoring - Live node discovery, telemetry, and message tracking across every connected source
- Modern UI - Catppuccin theme with message reactions and threading
- Interactive Maps - Unified node positions and network topology visualization across all sources
- Multi-Database Support - SQLite (default), PostgreSQL, and MySQL via Drizzle ORM
- Notifications - Web Push and Apprise integration for 100+ services
- Authentication - Local, OIDC/SSO, and reverse proxy authentication with RBAC
- Security Monitoring - Encryption key analysis and vulnerability detection
- Device Configuration - Full node configuration UI
- Virtual Node Server - Remote TCP access for Meshtastic Python clients
- REST API - v1 API with Bearer token authentication for external integrations
- Docker Ready - Pre-built multi-architecture images
- One-click Self-Upgrade - Automatic upgrades from the UI with backup and rollback
- System Backup & Restore - Complete disaster recovery with automated backups
For a complete feature list and technical details, visit meshmonitor.org.
- Node.js 20+
- Docker (recommended) or local Node.js environment
- At least one mesh source β a Meshtastic device (WiFi/Ethernet, or Serial/BLE via bridge), a MeshCore device, or an MQTT broker
# Clone with submodules
git clone --recurse-submodules https://github.com/Yeraze/meshmonitor.git
cd meshmonitor
# Install dependencies
npm install
# Configure environment
cp .env.example .env
# Edit .env to seed the first source (MESHTASTIC_NODE_IP / MESHTASTIC_TCP_PORT); additional nodes are added later via Dashboard β Sources
# Start development servers
npm run dev:fullThis starts both the React dev server (port 5173) and the Express API server (port 3001).
Development:
npm run dev- Start React development servernpm run dev:server- Start Express API servernpm run dev:full- Start both development serversnpm run build- Build React app for productionnpm run build:server- Build Express server for production
Testing & Quality:
npm run test- Run tests in watch modenpm run test:run- Run all tests oncenpm run test:coverage- Generate coverage reportnpm run lint- Run ESLintnpm run typecheck- Run TypeScript compiler checks
Frontend:
- React 19 with TypeScript
- Vite 7 (build tool)
- CSS3 with Catppuccin theme
- Translation support crowdsourced by Weblate
Backend:
- Node.js with Express 5
- TypeScript
- Drizzle ORM with SQLite, PostgreSQL, and MySQL drivers
DevOps:
- Docker with multi-stage builds
- Docker Compose for orchestration
- GitHub Container Registry for images
We welcome contributions! Please see our Contributing Guide for details on:
- Development setup
- Testing requirements
- Code style guidelines
- Pull request process
- CI/CD workflows
Quick start:
- Fork the repository
- Create a feature branch (
git checkout -b feature/amazing-feature) - Make your changes and add tests
- Run tests locally (
npm run test:run) - Commit with conventional commits (
feat: add amazing feature) - Push and create a Pull Request
This project is licensed under the BSD-3-Clause License - see the LICENSE file for details.
- Discord: Join our Discord - Chat with the community and get help
- GitHub Issues: Report bugs and request features
- Documentation: meshmonitor.org
- meshmonitor-chat.el - Emacs chat client using the REST API v1. Channel and DM support, delivery confirmation, emoji reactions, polling.
- MeshMonitor Chat for iOS - Native iOS chat client using the REST API v1. Channel and DM support over your MeshMonitor server.
- Meshtastic - Open source mesh networking
- Catppuccin - Soothing pastel theme
- React - Frontend framework
- Drizzle ORM - TypeScript ORM
- better-sqlite3 - SQLite driver
MeshMonitor - Monitor your mesh, beautifully. πβ¨
This application is brought to you with help from Claude Code.

