Configuration Overview β
MeshMonitor is designed to be flexible and adaptable to various deployment scenarios. This section covers all configuration options and deployment strategies.
Quick Start: Interactive Configurator
New! Use our Interactive Docker Compose Configurator to generate a customized docker-compose.yml and .env file for your specific setup. Just answer a few questions and get a ready-to-deploy configuration!
Supports: TCP/Network, BLE Bridge, Serial Bridge, reverse proxy, Virtual Node, and more.
Configuration Topics β
Serial Bridge for USB/Serial Devices β
Connect MeshMonitor to Serial or USB-connected Meshtastic devices using the Serial Bridge. Simple Docker-based TCP-to-Serial gateway with automatic device discovery.
BLE Bridge for Bluetooth Devices β
Connect MeshMonitor to Bluetooth Low Energy (BLE) Meshtastic devices using the BLE Bridge. Perfect for portable devices and systems with Bluetooth support.
Virtual Node Server β
Connect multiple Meshtastic mobile apps simultaneously through MeshMonitor's Virtual Node proxy. Configuration caching, message queuing, and connection stability for 3-5+ concurrent mobile clients. As of 4.11.0, a parallel MeshCore Virtual Node lets the MeshCore app connect to a managed MeshCore device over WiFi.
Using meshtasticd β
Learn how to configure MeshMonitor to work with meshtasticd, the virtual Meshtastic node daemon, perfect for testing and development without physical hardware.
SSO Setup β
Configure Single Sign-On (SSO) authentication using OpenID Connect (OIDC) for enterprise deployments and centralized identity management.
Reverse Proxy β
Set up NGINX, Apache, or other reverse proxies to handle SSL termination, load balancing, and secure external access to MeshMonitor.
HTTP vs HTTPS β
Understand the differences between HTTP and HTTPS deployments, security considerations, and how to configure SSL/TLS certificates.
HTTPS with DuckDNS β
Step-by-step guide for adding free DuckDNS dynamic DNS and Let's Encrypt certificates to a self-hosted MeshMonitor deployment.
Production Deployment β
Best practices and recommendations for deploying MeshMonitor in production environments, including high availability and monitoring.
Fail2ban Integration β
Protect your instance from brute-force attacks using fail2ban. Includes setup guide, AbuseIPDB integration, and advanced configuration options.
Push Notifications β
Configure push notifications for iOS, Android, and desktop browsers. Learn about HTTPS requirements, VAPID keys, and step-by-step setup guides for all platforms.
Custom Tile Servers β
Configure custom map tile servers for offline operation, custom styling, or organizational branding. Supports both vector (.pbf) and raster (.png) tiles with TileServer GL, nginx caching proxy, or any standard XYZ tile server.
Reducing Node Load β
Understand how MeshMonitor communicates with your Meshtastic node and how to tune settings to reduce memory pressure on constrained devices (ESP32, Heltec V3/V4, RAK4631).
Updating MeshMonitor β
How update notifications work, per-platform update instructions (Docker, LXC, Kubernetes/Helm, bare metal), and an unattended-updates recipe using Watchtower. Replaces the retired Automatic Self-Upgrade sidecar.
Environment Variables β
MeshMonitor can be configured using environment variables. Here are the most important ones:
Required Variables β
None. MeshMonitor boots with no environment variables set and you add your node(s) in Dashboard β Sources.
| Variable | Description | Example |
|---|---|---|
MESHTASTIC_NODE_IP | Optional. Seeds a Meshtastic TCP source on first boot | 192.168.1.100 |
MESHCORE_TCP_HOST / MESHCORE_SERIAL_PORT | Optional. Seeds a MeshCore source on first boot (details) | 192.168.1.60 / /dev/ttyACM0 |
Optional Variables β
| Variable | Description | Default |
|---|---|---|
PORT | Backend server port | 3001 |
SESSION_SECRET | Secret key for session encryption (REQUIRED in production) | Auto-generated |
NODE_ENV | Environment mode (development or production) | development |
DATABASE_PATH | SQLite database file path | /data/meshmonitor.db |
TRACEROUTE_HISTORY_LIMIT | Traceroute history rows to keep per node pair | 50 |
BASE_URL | Base path if serving from subfolder (e.g., /meshmonitor) | / (root) |
TZ | Timezone for log timestamps and scheduled tasks | America/New_York |
PUID / PGID | Docker: uid/gid of the unprivileged node user every process runs as. See Docker Security | 1000 / 1000 |
Meshtastic Connection Variables β
4.0 β bootstrap only
MESHTASTIC_NODE_IP and MESHTASTIC_TCP_PORT only bootstrap the first source on a fresh deployment. They are ignored after first boot. All subsequent source management β adding nodes, changing IPs/ports, switching connection type β happens in Dashboard β Sources. See Multi-Source.
4.16.1 β set it, or leave it out
Set MESHTASTIC_NODE_IP and a "Default" Meshtastic TCP source is created and connected on first boot. Leave it unset and the "Default" source is still created, but disabled, pointing at the placeholder host meshtastic.local. Nothing is dialled until you edit it with your node's address and enable it, or delete it and add your own sources.
If you set the MeshCore first-boot vars and leave MESHTASTIC_NODE_IP unset, the disabled placeholder is skipped: the only source is your MeshCore node.
Earlier versions used 192.168.1.100 as a stand-in when the variable was missing, created an enabled source pointing at it, and reconnected to that address forever. MeshCore-only and MQTT-only installs had no way to stop the resulting log spam, because deleting the source only made the next restart recreate it. MeshMonitor now connects to a Meshtastic node only when you have told it about one.
| Variable | Description | Default |
|---|---|---|
MESHTASTIC_NODE_IP | IP address used to seed the first TCP source on first boot. Unset β the Default source is created disabled (host meshtastic.local), or skipped when the MeshCore vars below are set | unset |
MESHTASTIC_TCP_PORT | TCP port used to seed the first TCP source on first boot | 4403 |
MESHTASTIC_STALE_CONNECTION_TIMEOUT | Connection timeout in milliseconds before reconnecting if no data received | 300000 (5 minutes) |
MESHTASTIC_CONNECT_TIMEOUT_MS | Initial TCP connection timeout in milliseconds | 10000 (10 seconds) |
MESHTASTIC_RECONNECT_INITIAL_DELAY_MS | Initial delay before first reconnect attempt (base for exponential backoff) | 1000 (1 second) |
MESHTASTIC_RECONNECT_MAX_DELAY_MS | Maximum delay between reconnect attempts (backoff cap) | 60000 (60 seconds) |
MESHTASTIC_MODULE_CONFIG_DELAY_MS | Delay between consecutive module config requests to avoid overwhelming the device | 100 (100ms) |
Virtual Node β
Virtual Node is a per source setting: each meshtastic_tcp source owns its own VN endpoint, and you manage it in Dashboard β Edit Source β Virtual Node.
For headless installs, two env vars can turn it on for the Default source when that source is first created:
| Variable | Description | Default |
|---|---|---|
ENABLE_VIRTUAL_NODE | true / 1 / yes adds a Virtual Node to the Default source on first boot. Needs MESHTASTIC_NODE_IP | unset (off) |
VIRTUAL_NODE_PORT | Port for that Virtual Node, 1β65535. Does nothing without ENABLE_VIRTUAL_NODE. An invalid value logs a warning and both vars are ignored | 4404 |
First boot only
These vars apply once, when the Default source is created. After that the source's saved config owns the Virtual Node settings, and later restarts never change them, even if you change or remove the vars. Change it in the UI from then on.
Admin commands stay off: there is no env var for them (VIRTUAL_NODE_ALLOW_ADMIN_COMMANDS was removed in 4.0 and is not coming back). The Virtual Node port has no login, so anyone who can reach it could reconfigure your node. Turn that on in the UI only if you trust every client that can reach the port.
See the Virtual Node Server guide for details.
MeshCore Default Source β
For a headless MeshCore install, these vars create a "Default MeshCore" source on first boot. They are independent of MESHTASTIC_NODE_IP: set either, both, or neither.
| Variable | Description | Default |
|---|---|---|
MESHCORE_TCP_HOST | Host of a MeshCore Companion reachable over TCP. Creates a TCP source | unset |
MESHCORE_TCP_PORT | Its TCP port. WiFi/Ethernet Companion builds listen on 5000 | 5000 |
MESHCORE_SERIAL_PORT | Serial path of a USB-attached device, e.g. /dev/ttyACM0. Creates a serial source. Map the device into the container with devices: | unset |
MESHCORE_BAUD_RATE | Serial baud rate | 115200 |
MESHCORE_DEVICE_TYPE | companion or repeater. A Repeater needs MESHCORE_SERIAL_PORT (no Repeater over TCP). Anything else logs a warning and uses companion | companion |
MESHCORE_ENABLE_VIRTUAL_NODE | true / 1 / yes adds a MeshCore Virtual Node to that source. Companion only | unset (off) |
MESHCORE_VIRTUAL_NODE_PORT | Port for that Virtual Node, 1β65535. Does nothing without MESHCORE_ENABLE_VIRTUAL_NODE | 5000 |
- Set
MESHCORE_TCP_HOSTorMESHCORE_SERIAL_PORT. If you set both, MeshMonitor logs a warning and uses TCP. Set neither and no MeshCore source is created. - The source is created enabled, with Auto-connect on and the same settings the Add Source form would save (Heartbeat 30 s for a Companion, off for a Repeater). It sends nothing over the radio that the same source added in the UI would not.
- The Virtual Node keeps Allow admin commands, Allow PKI export and Allow PKI import off. There are no env vars for them. If its port equals the Meshtastic Virtual Node port, MeshMonitor logs a warning and skips the MeshCore Virtual Node.
- With the MeshCore vars set and
MESHTASTIC_NODE_IPunset, the disabled Meshtastic placeholder is not created.
First boot only
Like MESHTASTIC_NODE_IP, these vars apply once, when MeshMonitor first creates its sources. An install that already has sources never grows a MeshCore source because you added the vars later, and later restarts never change the source, even if you change or remove the vars. Add or edit MeshCore sources in Dashboard β Sources from then on. (As with MESHTASTIC_NODE_IP, if you delete every source and restart with the vars still set, MeshMonitor treats the empty Sources list as a first boot and creates them again.)
See MeshCore β Headless installs.
Security & Reverse Proxy Variables β
| Variable | Description | Default |
|---|---|---|
TRUST_PROXY | Trust reverse proxy headers (required for HTTPS behind proxy) | 1 in production |
COOKIE_SECURE | Require HTTPS for cookies | true in production |
COOKIE_SAMESITE | Cookie SameSite policy (strict, lax, or none) | strict in production |
SESSION_COOKIE_NAME | Custom session cookie name (useful for multiple instances on same host) | meshmonitor.sid |
SESSION_MAX_AGE | Session cookie lifetime in milliseconds | 86400000 (24 hours) |
SESSION_ROLLING | Reset session expiry on each request (keeps active users logged in) | true |
ALLOWED_ORIGINS | REQUIRED for HTTPS/reverse proxy: Comma-separated list of allowed CORS origins | http://localhost:8080, http://localhost:3001 |
IFRAME_ALLOWED_ORIGINS | Comma-separated list of origins allowed to embed MeshMonitor in an <iframe> (e.g. a Node-RED dashboard). Use * to allow any origin. When unset, iframe embedding is blocked. | (unset - iframe blocked) |
WEBAUTHN_RP_ID | Hostname that passkeys bind to (bare hostname, no scheme or port). Optional. | request hostname |
WEBAUTHN_ORIGINS | Comma-separated origins allowed to use passkeys, for example https://mesh.example.com. Optional. | <scheme>://<host> of the request |
Embedding MeshMonitor in an iframe
By default MeshMonitor sends X-Frame-Options: DENY, which blocks browsers from rendering it inside an <iframe>. To embed MeshMonitor in another page (for example a Node-RED dashboard, Home Assistant panel, or internal portal), set IFRAME_ALLOWED_ORIGINS to the origin(s) that will host the frame:
environment:
# Allow a single Node-RED dashboard
- IFRAME_ALLOWED_ORIGINS=http://192.168.1.50:1880
# Or multiple origins
- IFRAME_ALLOWED_ORIGINS=http://192.168.1.50:1880,https://portal.example.com
# Or any origin (not recommended for production)
- IFRAME_ALLOWED_ORIGINS=*When set, MeshMonitor drops the X-Frame-Options header and enforces the same policy via CSP frame-ancestors. Only origins in the list (plus the server's own origin) can embed the UI.
Running Multiple Instances
If you're running multiple MeshMonitor instances on the same host (different ports), set SESSION_COOKIE_NAME to a unique value for each instance to avoid session cookie conflicts:
# First instance
- SESSION_COOKIE_NAME=meshmonitor-mf.sid
# Second instance
- SESSION_COOKIE_NAME=meshmonitor-lf.sidAuthentication Variables β
| Variable | Description | Default |
|---|---|---|
DISABLE_ANONYMOUS | Disable anonymous access - require login for all features | false |
DISABLE_LOCAL_AUTH | Disable local username/password authentication (OIDC only) | false |
ADMIN_USERNAME | Override default admin username on first run | admin |
ADMIN_PASSWORD | Password for the first admin, used only when that account is created on first boot. Never resets an existing admin's password. Must be at least 8 characters; an empty or shorter value logs a warning and falls back to changeme. Not printed in the log | changeme |
Rate Limiting Variables β
| Variable | Description | Default (Production) | Default (Development) |
|---|---|---|---|
RATE_LIMIT_API | Max API requests per 15 minutes | 1000 (~1 req/sec) | 10000 |
RATE_LIMIT_AUTH | Max auth attempts per 15 minutes | 5 | 100 |
RATE_LIMIT_MESSAGES | Max messages per minute | 30 | 100 |
Note: Rate limit violations are logged with IP address and path for troubleshooting. Adjust these values based on your usage patterns.
Access Logging Variables (for fail2ban) β
| Variable | Description | Default |
|---|---|---|
ACCESS_LOG_ENABLED | Enable Apache-style access logging for fail2ban integration | false |
ACCESS_LOG_PATH | Path to access log file | /data/logs/access.log |
ACCESS_LOG_FORMAT | Log format (combined, common, or tiny) | combined |
Note: Requires bind mount for host access. See Fail2ban Integration for complete setup guide.
SSO Variables (OIDC) β
| Variable | Description | Default |
|---|---|---|
OIDC_ISSUER | OIDC issuer URL | None (required for SSO) |
OIDC_CLIENT_ID | OIDC client ID | None (required for SSO) |
OIDC_CLIENT_SECRET | OIDC client secret | None (required for SSO) |
OIDC_REDIRECT_URI | Callback URL for OIDC | None (required for SSO) |
OIDC_SCOPES | Space-separated OIDC scopes to request | openid profile email |
OIDC_AUTO_CREATE_USERS | Automatically create users on first SSO login | true |
OIDC_GROUPS_CLAIM | ID-token claim with the user's groups (dot notation for nested, e.g. realm_access.roles) | groups |
OIDC_ADMIN_GROUPS | Comma-separated groups that grant admin rights | None |
OIDC_ALLOWED_GROUPS | Comma-separated groups allowed to log in (empty = all) | None |
OIDC_ALLOW_HTTP | Allow HTTP for OIDC (development only, not secure) | false |
See the SSO Setup guide for detailed OIDC configuration.
Push Notification Variables (Web Push) β
| Variable | Description | Default |
|---|---|---|
VAPID_PUBLIC_KEY | VAPID public key for web push notifications | None (required for push) |
VAPID_PRIVATE_KEY | VAPID private key for web push notifications | None (required for push) |
VAPID_SUBJECT | VAPID subject (email or URL for contact) | None (required for push) |
PUSH_NOTIFICATION_TTL | Time-to-live for push notifications in seconds (300-86400) | 3600 (1 hour) |
See the Push Notifications guide for setup instructions and key generation.
Logging Variables β
| Variable | Description | Default |
|---|---|---|
LOG_LEVEL | Log verbosity: trace, debug, info, warn, error | debug in development, info in production |
Note: LOG_LEVEL controls log output independently of NODE_ENV. This lets you enable debug logging in production Docker deployments without changing rate limits, cookie warnings, or other NODE_ENV-dependent behavior.
Branding Variables β
| Variable | Description | Default |
|---|---|---|
CUSTOM_TITLE | Overrides the "MeshMonitor" heading on the login page | MeshMonitor |
CUSTOM_LOGO_URL | Overrides the login-page logo with your own image (http(s), raster data:image β png/jpeg/gif/webp/avif, or same-origin relative URL) | built-in SVG |
Note: Both are optional and apply only to the login page. When unset β or when CUSTOM_LOGO_URL uses an unsupported scheme such as javascript: or a data:image/svg+xml URI (rejected because SVG can embed scripts) β MeshMonitor falls back to the default title and logo. Relative paths are resolved against the server's own origin.
System Management Variables β
| Variable | Description | Default |
|---|---|---|
DATA_DIR | Root directory for application data | /data |
BACKUP_DIR | Directory for database backups | /data/backups |
SYSTEM_BACKUP_DIR | Directory for full system backups | /data/system-backups |
RESTORE_FROM_BACKUP | Path to backup file to restore on startup | None |
VERSION_CHECK_DISABLED | Disable version check and hide update banner | false |
APPRISE_CONFIG_DIR | Directory for Apprise notification configuration | None |
DUPLICATE_KEY_SCAN_INTERVAL_HOURS | Hours between duplicate encryption key scans | 24 |
See the System Backup guide for backup and restore procedures.
Configuration Files β
Docker Compose β
For Docker deployments, configuration is typically done through environment variables in docker-compose.yml:
services:
meshmonitor:
image: meshmonitor:latest
environment:
- MESHTASTIC_NODE_IP=192.168.1.100
- PORT=3000
- SESSION_SECRET=your-secret-key-here
ports:
- "8080:8080"
volumes:
- meshmonitor_data:/app/dataKubernetes (Helm) β
For Kubernetes deployments, use the Helm chart values file:
# values.yaml
env:
meshtasticNodeIp: "192.168.1.100"
port: "3001"
ingress:
enabled: true
host: meshmonitor.example.com
tls:
enabled: trueFor environment variables not covered by the built-in chart fields (CORS, reverse proxy, database, sessions, etc.), use extraEnv:
extraEnv:
- name: ALLOWED_ORIGINS
value: "https://meshmonitor.example.com"
- name: TRUST_PROXY
value: "true"
- name: SESSION_SECRET
valueFrom:
secretKeyRef:
name: meshmonitor-secrets
key: session-secretThis accepts standard Kubernetes env var syntax, including valueFrom for Secrets and ConfigMaps.
See the Production Deployment guide for complete Helm configuration.
Database Configuration β
MeshMonitor uses SQLite for data storage by default. The database file is stored in the data/ directory.
Database Location β
- Docker:
/app/data/meshmonitor.db(mounted as a volume) - Bare Metal:
./data/meshmonitor.db(relative to project root)
Backup and Migration β
To backup your database:
# Docker
docker cp meshmonitor:/app/data/meshmonitor.db ./backup.db
# Bare Metal
cp data/meshmonitor.db backup.dbSecurity Considerations β
Session Secret β
Always set a strong SESSION_SECRET in production:
# Generate a secure random string
openssl rand -base64 32Database Encryption β
The database stores password hashes using bcrypt. User passwords are never stored in plain text.
HTTPS β
Always use HTTPS in production environments. See the HTTP vs HTTPS guide for setup instructions.
Logging β
MeshMonitor logs to stdout/stderr by default. Log output uses level prefixes: [DEBUG], [INFO], [WARN], [ERROR].
Log Levels β
Control verbosity with the LOG_LEVEL environment variable. Levels are cumulative β each includes everything above it in this table:
| Level | What is logged |
|---|---|
trace | Firehose β per-packet / per-loop diagnostics. Only enable for a short capture window; far too noisy for steady use. |
debug | Verbose but bounded β routine per-event activity, periodic scheduler cycles, connection handshake steps, state inspection. |
info | Default in production. Important, low-frequency events: startup/shutdown, source connect/disconnect, backups/restores/migrations, and deliberate actions taken. An idle container is near-silent at this level. |
warn | Warnings and errors only |
error | Errors only |
If LOG_LEVEL is not set, the default depends on NODE_ENV:
developmentortestβdebugproductionβinfo
Troubleshooting in Production
The default info level is deliberately quiet β routine per-packet, per-request, and periodic-scheduler activity is logged at debug. To investigate an issue, raise the level without changing NODE_ENV (this avoids side effects like altered rate limits or cookie warnings):
environment:
- NODE_ENV=production
- LOG_LEVEL=debug # or `trace` for the full per-packet firehoseLog Aggregation β
Configure log collection in your deployment platform:
- Docker: Use
docker logsor configure a logging driver - Kubernetes: Logs are available via
kubectl logs - Bare Metal: Redirect output to log files or use a process manager like systemd
Community Add-ons β
Looking for the MQTT Client Proxy, AI Responder, or other sidecar containers? These have moved to the Community Add-ons section.