mirror of
https://github.com/ipnet-mesh/meshcore-hub.git
synced 2026-06-29 22:41:48 +02:00
5fe8ce9156
Restrict which remote observers may ingest events, keyed on the observer's public key (the <public_key> segment of its LetsMesh upload topic). Anyone with broker access can publish as an observer via JWT auth, so operators can now gate ingestion. - New ObserverFilter (case-insensitive prefix matching, allowlist overrides denylist, accept-all when both empty) - New OBSERVER_ALLOWLIST / OBSERVER_DENYLIST collector settings, wired through the CLI, run_collector, create_subscriber, and Subscriber - Filter applied at the top of _handle_mqtt_message: blocked observers' packets are dropped before any decode, raw-packet capture, or DB write; zero added work on the default accept-all path - Tests: ObserverFilter unit tests, subscriber drop/allow integration tests, config parsing tests - Docs: configuration.md, observer.md, upgrading.md (v0.16.0), .env.example, docker-compose.yml Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
616 lines
21 KiB
Bash
616 lines
21 KiB
Bash
# MeshCore Hub - Environment Configuration
|
|
# Copy this file to .env and customize values
|
|
#
|
|
# Configuration is grouped by service. Most deployments only need:
|
|
# - Common Settings (always required)
|
|
# - MQTT Settings (always required)
|
|
# - Packet Capture Settings (for observer nodes)
|
|
#
|
|
# The Collector, API, and Web services typically run as a combined "core"
|
|
# profile and share the same data directory.
|
|
#
|
|
# -----------------------------------------------------------------------------
|
|
# QUICK START: Observer Node
|
|
# -----------------------------------------------------------------------------
|
|
# For an observer node capturing mesh traffic, you need:
|
|
#
|
|
# MQTT_HOST=your-mqtt-broker.example.com
|
|
# MQTT_PORT=1883
|
|
# MQTT_USERNAME=your_username
|
|
# MQTT_PASSWORD=your_password
|
|
# MQTT_TLS=false
|
|
# SERIAL_PORT=/dev/ttyUSB0
|
|
#
|
|
# Serial ports are typically /dev/ttyUSB[0-9] or /dev/ttyACM[0-9] on Linux.
|
|
# -----------------------------------------------------------------------------
|
|
# -----------------------------------------------------------------------------
|
|
|
|
# =============================================================================
|
|
# COMMON SETTINGS
|
|
# =============================================================================
|
|
# These settings apply to all services
|
|
|
|
# Docker Compose project name
|
|
# Used as a prefix for container names (e.g., hub-api) and volume names
|
|
# (e.g., hub_data). Change per instance when running multiple deployments
|
|
# on the same Docker host (e.g., hub-prod, hub-beta, hub-stg).
|
|
# For multi-instance setups, see docs/deployment.md.
|
|
COMPOSE_PROJECT_NAME=hub
|
|
|
|
# Domain name for this instance (only needed for Traefik deployments)
|
|
# Used by docker-compose.traefik.yml to configure routing rules
|
|
# TRAEFIK_DOMAIN=meshcore.example.com
|
|
|
|
# Router priority for Traefik (higher = matched first)
|
|
# Use a higher value for more specific subdomain instances to avoid
|
|
# conflicts with wildcard routes from other instances on the same host.
|
|
# Production: 10 (default)
|
|
# Staging: 20
|
|
# MQTT broker: 30
|
|
# TRAEFIK_PRIORITY=10
|
|
|
|
# Docker image version tag to use
|
|
# Options: latest, main, v1.0.0, etc.
|
|
IMAGE_VERSION=latest
|
|
|
|
# Logging level (DEBUG, INFO, WARNING, ERROR, CRITICAL)
|
|
LOG_LEVEL=INFO
|
|
|
|
# Base directory for runtime data (database, etc.)
|
|
# Default: ./data (relative to docker-compose.yml location)
|
|
# Inside containers this is mapped to /data
|
|
#
|
|
# Structure:
|
|
# ${DATA_HOME}/
|
|
# └── collector/
|
|
# └── meshcore.db # SQLite database
|
|
DATA_HOME=./data
|
|
|
|
# -----------------------------------------------------------------------------
|
|
# Database
|
|
# -----------------------------------------------------------------------------
|
|
# SQLite is the zero-config default and needs nothing here — it lives at
|
|
# ${DATA_HOME}/collector/meshcore.db.
|
|
#
|
|
# To use PostgreSQL instead, set DATABASE_BACKEND=postgres and fill in the
|
|
# DATABASE_* values below (the bundled postgres container derives its
|
|
# POSTGRES_USER/PASSWORD/DB from DATABASE_USER/PASSWORD/NAME). You must also
|
|
# activate the compose 'postgres' profile, e.g. `docker compose --profile postgres up`.
|
|
#
|
|
# See docs/database.md for the full backend reference: production role/database
|
|
# provisioning, managed/external Postgres, and schema-per-instance (search_path)
|
|
# isolation for multiple instances sharing one cluster.
|
|
#
|
|
# DATABASE_BACKEND=postgres
|
|
# DATABASE_HOST=postgres
|
|
# DATABASE_PORT=5432
|
|
# DATABASE_NAME=meshcorehub
|
|
# DATABASE_SCHEMA=meshcorehub # override per instance (e.g. prod, stg) on a shared cluster
|
|
# DATABASE_USER=meshcorehub
|
|
# DATABASE_PASSWORD= # required for postgres; e.g. `openssl rand -base64 32`
|
|
#
|
|
# Advanced: set DATABASE_URL to a full SQLAlchemy URL to override all of the above
|
|
# (e.g. a managed/external Postgres). Takes precedence over DATABASE_BACKEND.
|
|
# DATABASE_URL=postgresql+psycopg2://user:pass@host:5432/dbname
|
|
|
|
# Directory containing seed data files for import
|
|
# Default: ./seed (relative to docker-compose.yml location)
|
|
# Inside containers this is mapped to /seed
|
|
#
|
|
# Structure:
|
|
# ${SEED_HOME}/
|
|
# └── node_tags.yaml # Node tags for import
|
|
SEED_HOME=./seed
|
|
|
|
# =============================================================================
|
|
# MQTT SETTINGS
|
|
# =============================================================================
|
|
# MQTT broker connection settings for collector and API services
|
|
# Uses the MeshCore MQTT broker (WebSocket transport with subscriber auth)
|
|
# See: https://github.com/michaelhart/meshcore-mqtt-broker
|
|
|
|
# MQTT Broker host
|
|
# When using the local MQTT broker (--profile mqtt), use "mqtt"
|
|
# When using an external broker, set the hostname/IP
|
|
# For native (non-Docker) installs, use "localhost" (the Python default)
|
|
MQTT_HOST=mqtt
|
|
|
|
# MQTT Broker port
|
|
# Default: 1883 (local, plain WebSocket)
|
|
# Production behind reverse proxy: 8883 (TLS)
|
|
MQTT_PORT=1883
|
|
|
|
# MQTT subscriber authentication
|
|
# The broker uses subscriber accounts with roles:
|
|
# Role 1 (admin): full access including /internal topics
|
|
# Role 2 (full_access): all public topics, no filtering
|
|
# Role 3 (limited): filtered data (SNR, RSSI, etc. removed)
|
|
MQTT_USERNAME=
|
|
MQTT_PASSWORD=
|
|
|
|
# MQTT topic prefix for all MeshCore messages
|
|
MQTT_PREFIX=meshcore
|
|
|
|
# Enable TLS/SSL for MQTT connection
|
|
# Set to true when connecting via wss:// (e.g., behind a reverse proxy)
|
|
MQTT_TLS=false
|
|
|
|
# MQTT transport protocol
|
|
# The MeshCore MQTT broker uses WebSockets exclusively
|
|
MQTT_TRANSPORT=websockets
|
|
|
|
# MQTT WebSocket path (used when MQTT_TRANSPORT=websockets)
|
|
# Default: / (broker accepts any path)
|
|
# Production: can be set to /mqtt if reverse proxy rewrites paths
|
|
MQTT_WS_PATH=/
|
|
|
|
# JWT audience claim for packet capture authentication tokens
|
|
# Must match AUTH_EXPECTED_AUDIENCE on the broker
|
|
# Local default: mqtt.localhost
|
|
# Production: set to your broker's domain (e.g., mqtt.example.com)
|
|
MQTT_TOKEN_AUDIENCE=mqtt.localhost
|
|
|
|
# =============================================================================
|
|
# PACKET CAPTURE SETTINGS
|
|
# =============================================================================
|
|
# External packet capture service (ghcr.io/agessaman/meshcore-packet-capture)
|
|
# See https://github.com/agessaman/meshcore-packet-capture for documentation.
|
|
# Uses the "observer" compose profile.
|
|
# Publishes captured packets to MQTT in LetsMesh upload format, ingested by
|
|
# the collector.
|
|
|
|
# Serial port for the packet capture device
|
|
SERIAL_PORT=/dev/ttyUSB0
|
|
|
|
# Docker image version tag for the packet capture image
|
|
PACKETCAPTURE_IMAGE_VERSION=latest
|
|
|
|
# Connection timeout and retry settings
|
|
PACKETCAPTURE_TIMEOUT=30
|
|
PACKETCAPTURE_MAX_CONNECTION_RETRIES=5
|
|
PACKETCAPTURE_CONNECTION_RETRY_DELAY=5
|
|
PACKETCAPTURE_HEALTH_CHECK_INTERVAL=30
|
|
|
|
# IATA airport code identifier (used in Let's Mesh topic templates)
|
|
PACKETCAPTURE_IATA=LOC
|
|
|
|
# Device display name (optional, defaults to device name from meshcore connection)
|
|
# PACKETCAPTURE_ORIGIN=
|
|
|
|
# Send flood adverts at this interval in hours (0 = disabled)
|
|
PACKETCAPTURE_ADVERT_INTERVAL_HOURS=11
|
|
|
|
# RF data cache timeout in seconds
|
|
PACKETCAPTURE_RF_DATA_TIMEOUT=15.0
|
|
|
|
# -------------------
|
|
# Let's Mesh MQTT Brokers (opt-in)
|
|
# -------------------
|
|
# Enable to publish captured packets to the Let's Mesh cloud map
|
|
|
|
# Broker 1 - Let's Mesh US
|
|
PACKETCAPTURE_MQTT1_ENABLED=false
|
|
PACKETCAPTURE_MQTT1_SERVER=mqtt-us-v1.letsmesh.net
|
|
PACKETCAPTURE_MQTT1_PORT=443
|
|
PACKETCAPTURE_MQTT1_USE_TLS=true
|
|
PACKETCAPTURE_MQTT1_USE_AUTH_TOKEN=true
|
|
PACKETCAPTURE_MQTT1_TOKEN_AUDIENCE=mqtt-us-v1.letsmesh.net
|
|
PACKETCAPTURE_MQTT1_KEEPALIVE=120
|
|
|
|
# Broker 2 - Let's Mesh EU
|
|
PACKETCAPTURE_MQTT2_ENABLED=false
|
|
PACKETCAPTURE_MQTT2_SERVER=mqtt-eu-v1.letsmesh.net
|
|
PACKETCAPTURE_MQTT2_PORT=443
|
|
PACKETCAPTURE_MQTT2_USE_TLS=true
|
|
PACKETCAPTURE_MQTT2_USE_AUTH_TOKEN=true
|
|
PACKETCAPTURE_MQTT2_TOKEN_AUDIENCE=mqtt-eu-v1.letsmesh.net
|
|
PACKETCAPTURE_MQTT2_KEEPALIVE=120
|
|
|
|
# Broker 3 - Local MQTT (enabled by default, wired to hub's MQTT_* settings)
|
|
# Uses websockets and auth tokens by default (set in docker-compose.yml)
|
|
PACKETCAPTURE_MQTT3_ENABLED=true
|
|
PACKETCAPTURE_MQTT3_KEEPALIVE=60
|
|
|
|
# MQTT reconnection settings
|
|
PACKETCAPTURE_MAX_MQTT_RETRIES=5
|
|
PACKETCAPTURE_MQTT_RETRY_DELAY=5
|
|
PACKETCAPTURE_EXIT_ON_RECONNECT_FAIL=true
|
|
|
|
# =============================================================================
|
|
# COLLECTOR SETTINGS
|
|
# =============================================================================
|
|
# The collector subscribes to MQTT events and stores them in the database
|
|
|
|
# Refresh interval for reloading channel keys from the database (seconds).
|
|
# CHANNEL_REFRESH_INTERVAL_SECONDS=300
|
|
|
|
# -------------------
|
|
# Webhook Settings
|
|
# -------------------
|
|
# Webhooks forward mesh events to external HTTP endpoints as POST requests
|
|
|
|
# Webhook for advertisement events (node discovery)
|
|
WEBHOOK_ADVERTISEMENT_URL=
|
|
WEBHOOK_ADVERTISEMENT_SECRET=
|
|
|
|
# Webhook for all message events (channel and direct messages)
|
|
WEBHOOK_MESSAGE_URL=
|
|
WEBHOOK_MESSAGE_SECRET=
|
|
|
|
# Optional: Separate URLs for channel vs direct messages
|
|
# These override WEBHOOK_MESSAGE_URL if set
|
|
# WEBHOOK_CHANNEL_MESSAGE_URL=
|
|
# WEBHOOK_CHANNEL_MESSAGE_SECRET=
|
|
# WEBHOOK_DIRECT_MESSAGE_URL=
|
|
# WEBHOOK_DIRECT_MESSAGE_SECRET=
|
|
|
|
# Webhook behavior settings
|
|
WEBHOOK_TIMEOUT=10.0
|
|
WEBHOOK_MAX_RETRIES=3
|
|
WEBHOOK_RETRY_BACKOFF=2.0
|
|
|
|
# -------------------
|
|
# Data Retention Settings
|
|
# -------------------
|
|
# Automatic cleanup of old event data (advertisements, messages, telemetry, etc.)
|
|
|
|
# Enable automatic cleanup of old event data
|
|
DATA_RETENTION_ENABLED=true
|
|
|
|
# Number of days to retain event data
|
|
# Events older than this are deleted during cleanup
|
|
DATA_RETENTION_DAYS=30
|
|
|
|
# Hours between automatic cleanup runs
|
|
# Applies to both event data and node cleanup
|
|
DATA_RETENTION_INTERVAL_HOURS=24
|
|
|
|
# -------------------
|
|
# Raw Packet Capture
|
|
# -------------------
|
|
# Capture every inbound packets-feed packet into the raw_packets table.
|
|
# Off by default. In Docker Compose this is derived from FEATURE_PACKETS, so
|
|
# setting FEATURE_PACKETS=true enables both capture and the Packets page.
|
|
# RAW_PACKET_CAPTURE_ENABLED=false
|
|
|
|
# Days to retain raw packets before cleanup. Defaults to 7, independent of
|
|
# DATA_RETENTION_DAYS. The raw_packets table grows fastest of all; lower this on
|
|
# busy meshes or constrained storage. Retention runs regardless of capture being
|
|
# enabled, so disabling capture lets existing rows drain.
|
|
# RAW_PACKET_RETENTION_DAYS=7
|
|
|
|
# -------------------------
|
|
# Observer Ingestion Filter
|
|
# -------------------------
|
|
# Restrict which remote observers may ingest events, keyed on the observer's
|
|
# public key (the <public_key> segment of its LetsMesh upload topic). Both lists
|
|
# are comma-separated. The allowlist takes precedence over the denylist, and
|
|
# matching is case-insensitive PREFIX matching (a full 64-char key or a shorter
|
|
# prefix both work). Blocked packets are dropped before any decode or DB write.
|
|
# Leave both empty to accept all observers (default).
|
|
# OBSERVER_ALLOWLIST=
|
|
# OBSERVER_DENYLIST=
|
|
|
|
# -------------------
|
|
# Spam Detection
|
|
# -------------------
|
|
# Score each message's spam likelihood at ingest and hide likely-spam by default
|
|
# (with a "show potential spam" toggle on the Messages page). Nothing is ever
|
|
# dropped; the score is stored and the display layer filters on it.
|
|
#
|
|
# On by default. FEATURE_SPAM_DETECTION is the single switch operators set: in
|
|
# Docker Compose it drives the backend SPAM_DETECTION_ENABLED for the collector
|
|
# (scoring + sweep) and the api (hide-filter), and exposes the UI toggle. Opt out
|
|
# by setting it to false.
|
|
# FEATURE_SPAM_DETECTION=true
|
|
|
|
# Backend operational switch, read by the collector + api. Compose derives it from
|
|
# FEATURE_SPAM_DETECTION (SPAM_DETECTION_ENABLED=${FEATURE_SPAM_DETECTION}); set it
|
|
# directly only when running the services without Compose.
|
|
# SPAM_DETECTION_ENABLED=true
|
|
|
|
# Score at/above which a message is treated as likely spam (hidden by default in
|
|
# the API, logged at WARNING by the collector). Read by the collector + api.
|
|
# SPAM_SCORE_THRESHOLD=0.65
|
|
|
|
# Scoring tuning (collector only; only consulted when detection is enabled).
|
|
# SPAM_WINDOW_SECONDS=300 # sliding window for frequency counts
|
|
# SPAM_PATH_HOPS=3 # leading origin-side hops that form the prefix
|
|
# SPAM_MIN_PATH_HOPS=3 # min path_len before the path signal applies
|
|
# SPAM_PATH_THRESHOLD=6 # joint path+sender count that saturates the path signal
|
|
# SPAM_NAME_THRESHOLD=10 # sender count that saturates the name signal
|
|
# SPAM_WEIGHT_PATH=0.75 # weight of the path signal
|
|
# SPAM_WEIGHT_NAME=0.25 # weight of the name signal
|
|
# SPAM_RESCORE_INTERVAL_SECONDS=120 # background re-scoring sweep cadence (0 disables)
|
|
|
|
# -------------------
|
|
# Node Cleanup Settings
|
|
# -------------------
|
|
# Automatic removal of inactive nodes
|
|
|
|
# Enable automatic cleanup of inactive nodes
|
|
# Nodes with last_seen=NULL (never seen on network) are NOT removed
|
|
NODE_CLEANUP_ENABLED=true
|
|
|
|
# Remove nodes not seen for this many days (based on last_seen field)
|
|
NODE_CLEANUP_DAYS=30
|
|
|
|
# =============================================================================
|
|
# API SETTINGS
|
|
# =============================================================================
|
|
# REST API for querying data
|
|
|
|
# External API port
|
|
API_PORT=8000
|
|
|
|
# Number of API worker processes (default 1). Increase to use multiple CPU
|
|
# cores under load — each worker is an independent process sharing the same
|
|
# listening socket. All workers read configuration from these env vars.
|
|
# API_WORKERS=1
|
|
|
|
# API Keys for authentication
|
|
# Generate secure keys for production: openssl rand -hex 32
|
|
# Leave empty to disable authentication (not recommended for production)
|
|
API_READ_KEY=
|
|
API_ADMIN_KEY=
|
|
|
|
# -------------------
|
|
# Prometheus Metrics
|
|
# -------------------
|
|
# Prometheus metrics endpoint exposed at /metrics on the API service
|
|
|
|
# Enable Prometheus metrics endpoint
|
|
# Default: true
|
|
METRICS_ENABLED=true
|
|
|
|
# Seconds to cache metrics output (reduces database load)
|
|
# Default: 60
|
|
METRICS_CACHE_TTL=60
|
|
|
|
# CORS origins for the API server (comma-separated)
|
|
# Only needed when running the web dashboard on a different origin than the API
|
|
# Example: http://localhost:8080,http://localhost:3000
|
|
# CORS_ORIGINS=
|
|
|
|
# External Prometheus port (when using --profile metrics)
|
|
PROMETHEUS_PORT=9090
|
|
|
|
# -------------------
|
|
# Redis Cache
|
|
# -------------------
|
|
# Optional Redis cache for API response caching.
|
|
# Reduces database load for read-heavy endpoints (nodes, messages, dashboard).
|
|
# When disabled or unavailable, the API queries the database directly.
|
|
#
|
|
# Docker: Redis is included in the "cache" profile (--profile cache).
|
|
# REDIS_ENABLED defaults to false everywhere. To enable, set REDIS_ENABLED=true
|
|
# and start with --profile cache (or point REDIS_HOST at an external Redis).
|
|
# Bare-metal: Install Redis separately and set REDIS_ENABLED=true.
|
|
#
|
|
# For multi-instance setups sharing one Redis, use different REDIS_KEY_PREFIX
|
|
# values per instance (e.g., hub for prod, hub-stg for staging).
|
|
|
|
# Enable Redis caching (default: false outside Docker, true in Docker Compose)
|
|
# REDIS_ENABLED=false
|
|
|
|
# Redis server host (use "redis" in Docker Compose)
|
|
# REDIS_HOST=localhost
|
|
|
|
# Redis server port
|
|
# REDIS_PORT=6379
|
|
|
|
# Redis database number
|
|
# REDIS_DB=0
|
|
|
|
# Redis password (optional)
|
|
# REDIS_PASSWORD=
|
|
|
|
# Cache key prefix for multi-instance isolation
|
|
# REDIS_KEY_PREFIX=hub
|
|
|
|
# Default cache TTL in seconds (matches web auto-refresh interval)
|
|
# REDIS_CACHE_TTL=30
|
|
|
|
# Cache TTL for dashboard endpoints (seconds)
|
|
# REDIS_CACHE_TTL_DASHBOARD=30
|
|
|
|
# External Alertmanager port (when using --profile metrics)
|
|
ALERTMANAGER_PORT=9093
|
|
|
|
# =============================================================================
|
|
# WEB DASHBOARD SETTINGS
|
|
# =============================================================================
|
|
# Web interface for visualizing network status
|
|
|
|
# External web port
|
|
WEB_PORT=8080
|
|
|
|
# API endpoint URL for the web dashboard
|
|
# Default: http://localhost:8000
|
|
# API_BASE_URL=http://localhost:8000
|
|
|
|
# API key for web dashboard queries (optional)
|
|
# If API_READ_KEY is set on the API, provide it here
|
|
# API_KEY=
|
|
|
|
# Default theme for the web dashboard (dark or light)
|
|
# Users can override via the theme toggle; their preference is saved in localStorage
|
|
# Default: dark
|
|
# WEB_THEME=dark
|
|
|
|
# Locale/language for the web dashboard
|
|
# Default: en
|
|
# Supported: en, nl (see src/meshcore_hub/web/static/locales/ for available translations)
|
|
# WEB_LOCALE=en
|
|
|
|
# Locale used for date/time formatting in the web dashboard
|
|
# Controls date ordering only; 24-hour clock is still used by default
|
|
# Examples: en-US (MM/DD/YYYY), en-GB (DD/MM/YYYY)
|
|
# Default: en-US
|
|
# WEB_DATETIME_LOCALE=en-US
|
|
|
|
# Auto-refresh interval in seconds for list pages (nodes, advertisements, messages)
|
|
# Set to 0 to disable auto-refresh
|
|
# Default: 30
|
|
# WEB_AUTO_REFRESH_SECONDS=30
|
|
|
|
# Enable debug mode in the web dashboard
|
|
# Shows extra diagnostic info (e.g., raw user IDs in the user menu)
|
|
# Default: false
|
|
# WEB_DEBUG=false
|
|
|
|
# -------------------
|
|
# OIDC Authentication
|
|
# -------------------
|
|
# Enable OIDC/OAuth2 authentication for the web dashboard.
|
|
# When enabled, the admin interface (/a/) requires authenticated sessions.
|
|
# Requires an OIDC-compliant identity provider (e.g., LogTo, Keycloak).
|
|
|
|
# Enable OIDC authentication
|
|
# Default: false
|
|
# OIDC_ENABLED=false
|
|
|
|
# OIDC client ID (from your IdP)
|
|
# OIDC_CLIENT_ID=
|
|
|
|
# OIDC client secret (from your IdP)
|
|
# OIDC_CLIENT_SECRET=
|
|
|
|
# OIDC discovery base URL (.well-known/openid-configuration is appended automatically)
|
|
# OIDC_DISCOVERY_URL=
|
|
|
|
# OIDC callback URL (overrides auto-derivation from request)
|
|
# Example: https://hub.example.com/auth/callback
|
|
# OIDC_REDIRECT_URI=
|
|
|
|
# Post-logout redirect URI (must match Sign-out redirect URIs configured in IdP)
|
|
# Falls back to OIDC_REDIRECT_URI base or request.base_url if not set
|
|
# Example: https://hub.example.com/
|
|
# OIDC_POST_LOGOUT_REDIRECT_URI=
|
|
|
|
# OAuth scopes to request. The 'openid' scope is required for ID tokens
|
|
# and userinfo endpoint access. Quotes around the value are stripped automatically.
|
|
# Default: openid email profile
|
|
# OIDC_SCOPES="openid email profile"
|
|
|
|
# ID token claim name containing user roles
|
|
# Default: roles
|
|
# OIDC_ROLES_CLAIM=roles
|
|
|
|
# IdP role name that grants admin access
|
|
# Default: admin
|
|
# OIDC_ROLE_ADMIN=admin
|
|
|
|
# IdP role name for operator access (future use)
|
|
# Default: operator
|
|
# OIDC_ROLE_OPERATOR=operator
|
|
|
|
# IdP role name for member access
|
|
# Default: member
|
|
# OIDC_ROLE_MEMBER=member
|
|
|
|
# IdP role name for test users (excluded from public member views and counts)
|
|
# Default: test
|
|
# OIDC_ROLE_TEST=test
|
|
|
|
# Secret for signing session cookies (required when OIDC_ENABLED=true)
|
|
# Generate with: openssl rand -hex 32
|
|
# OIDC_SESSION_SECRET=
|
|
|
|
# Session cookie lifetime in seconds
|
|
# Default: 86400 (24 hours)
|
|
# OIDC_SESSION_MAX_AGE=86400
|
|
|
|
# HTTPS-only session cookies (enable in production behind TLS)
|
|
# Default: false
|
|
# OIDC_COOKIE_SECURE=false
|
|
|
|
# Timezone for displaying dates/times on the web dashboard
|
|
# Uses standard IANA timezone names (e.g., America/New_York, Europe/London)
|
|
# Default: UTC
|
|
TZ=UTC
|
|
|
|
# Directory containing custom content (pages/, media/)
|
|
# Default: ./content
|
|
# CONTENT_HOME=./content
|
|
|
|
# -------------------
|
|
# Network Information
|
|
# -------------------
|
|
# Displayed on the web dashboard homepage
|
|
|
|
# Network domain name (optional)
|
|
# NETWORK_DOMAIN=
|
|
|
|
# Network display name
|
|
NETWORK_NAME=MeshCore Network
|
|
|
|
# Network location
|
|
NETWORK_CITY=
|
|
NETWORK_COUNTRY=
|
|
|
|
# Radio configuration (six individual variables — no unit suffixes needed)
|
|
# Units (MHz, kHz, dBm) are applied automatically on display
|
|
NETWORK_RADIO_PROFILE=EU/UK Narrow
|
|
NETWORK_RADIO_FREQUENCY=869.618
|
|
NETWORK_RADIO_BANDWIDTH=62.5
|
|
NETWORK_RADIO_SPREADING_FACTOR=8
|
|
NETWORK_RADIO_CODING_RATE=8
|
|
NETWORK_RADIO_TX_POWER=22
|
|
|
|
# Welcome text displayed on the homepage (optional, plain text)
|
|
# If not set, a default welcome message is shown
|
|
NETWORK_WELCOME_TEXT=
|
|
|
|
# Flash banner announcement displayed on all pages (optional, Markdown supported)
|
|
# Supports bold, italic, links, inline code. Empty = no banner shown.
|
|
# Example: **Maintenance** scheduled for Saturday — see [details](https://example.com)
|
|
NETWORK_ANNOUNCEMENT=
|
|
|
|
# System announcement banner (optional, Markdown supported)
|
|
# Non-dismissable banner shown above the network announcement on every page,
|
|
# for important system notices (downtime, maintenance windows, alerts).
|
|
# Stays visible until unset and the web service is restarted. Empty = no banner.
|
|
SYSTEM_ANNOUNCEMENT=
|
|
|
|
# Maintenance mode (default: false)
|
|
# When true, disables almost all site functionality: the nav shows only Home,
|
|
# the user/profile menu is hidden, and every page renders a "Site Under
|
|
# Maintenance" notice. No backend API calls are made, so the API/database can
|
|
# be offline while the web component keeps running. Requires a web restart.
|
|
SYSTEM_MAINTENANCE=false
|
|
|
|
# -------------------
|
|
# Feature Flags
|
|
# -------------------
|
|
# Control which pages are visible in the web dashboard
|
|
# Set to false to completely hide a page (nav, routes, sitemap, robots.txt)
|
|
|
|
# FEATURE_DASHBOARD=true
|
|
# FEATURE_NODES=true
|
|
# FEATURE_ADVERTISEMENTS=true
|
|
# FEATURE_MESSAGES=true
|
|
# FEATURE_MAP=true
|
|
# FEATURE_MEMBERS=true
|
|
# FEATURE_PAGES=true
|
|
# FEATURE_CHANNELS=true
|
|
# FEATURE_RADIO_CONFIG=true
|
|
# Packets page is ON by default. This var also drives raw-packet capture
|
|
# on the collector via Compose (RAW_PACKET_CAPTURE_ENABLED=${FEATURE_PACKETS}).
|
|
# FEATURE_PACKETS=true
|
|
# Spam detection is ON by default. This var also drives the backend scoring +
|
|
# hide switch on the collector/api via Compose
|
|
# (SPAM_DETECTION_ENABLED=${FEATURE_SPAM_DETECTION}). Set to false to opt out.
|
|
# See the Spam Detection section above for the scoring tuning vars.
|
|
# FEATURE_SPAM_DETECTION=true
|
|
|
|
# -------------------
|
|
# Contact Information
|
|
# -------------------
|
|
# Contact links displayed in the footer
|
|
|
|
NETWORK_CONTACT_EMAIL=
|
|
NETWORK_CONTACT_DISCORD=
|
|
NETWORK_CONTACT_GITHUB=
|
|
NETWORK_CONTACT_YOUTUBE=
|