CLI tool
Yeraze/meshmonitor avatar
Yeraze/meshmonitor

MeshMonitor's quick start omits the MQTT port its own compose file publishes

Web tool for monitoring Mesh Node Deployment over TCP/HTTP

728 stars111 forksTypeScriptBSD-3-Clause

At a glance

What is it?
A dashboard for off-grid mesh networks in React and TypeScript, with three databases, a Helm chart, and a root directory holding sixty entries. The two-minute install and the repository's own compose file are not the same configuration.
Who is it for?
MeshMonitor is the most operationally serious project in this set and its documentation is unusually honest about failure modes, including the ones that would embarrass a vendor. Read the proxy authentication section before you put it behind anything, because the three requirements it lists are not optional and one of them changed default in a recent version.
Can I use it commercially?
Yes. BSD-3-Clause is a permissive licence: you can use, modify and sell software built on it, as long as you keep its copyright and licence notices.
Is it still maintained?
Yes. The repository received new commits within the last day.
What is it written in?
Mainly TypeScript, according to GitHub's language statistics.

Answers come from the project's GitHub data, last synced on November 14, 2026, and from our analysis. They are not legal advice.

From daily snapshots

Star history

  • Yeraze/meshmonitor728 ★ · +138
Star history
Repository2026-08-012026-11-14
Yeraze/meshmonitor590728

138 Stars in the last 105 days, measured from the daily GitHub snapshot. Compare with other projects

Editorial analysis

The default login is documented in capitals and two admin scripts sit at the root

The quick start tells you the default credentials in the same line as the port:

Default login: `admin` / `changeme`, with a parenthetical to change it after the first login.

That is the right way to document a default credential, because the alternative is a user finding it the hard way. It is still a default credential on a network-attached web application, and the parenthetical is the only thing between it and a deployment somebody forgets.

What makes it more than a documentation note is the root directory. Alongside the readme there are two scripts whose names are about the admin account: one that checks it and one that resets it. Both are committed at the top level rather than in the scripts directory.

So the repository carries three separate things about the same account: a documented default password, a check script and a reset script.

A reset script at the root of a deployment-oriented project is not a flaw in itself, since operators need a way back in. But it means anyone evaluating this project should find out what that script does before it is on their filesystem, and nothing in the readme mentions it.

The readme also carries a translation-platform badge, and the project has a script that checks user-interface glyphs per locale, so localisation is a real concern here. The readme you get is English only, which means the installation instructions in other languages are maintained somewhere you cannot see from here.

The quick start publishes one port and the shipped compose file publishes two

Here is the entire quick start:

bash
# 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:8080

Now compare it with the compose file the repository actually ships, which sets two ports. The second publishes a broker port in addition to the dashboard port, and its comment names the issue number it came from and tells you to comment it out if you already run a broker.

So the quick start gives you a dashboard with no broker, and the project's own file gives you both.

The environment differs too. The shipped file sets a runtime mode, a timezone and an allowed-origins value, and marks that last one as required for cross-origin behaviour. The quick start sets none of the three. A user who follows the quick start gets a container with no allowed-origins configuration while the maintainers' own file calls it required.

The shipped file also documents a log-verbosity setting with per-level defaults and an explanation that the default is deliberately quiet, listing what gets logged and telling you to raise it when troubleshooting. None of that is in the quick start.

The gap is not dangerous. It is just two configurations with one name.

Sixty top-level entries, including a log file and two plan documents

The repository root has sixty entries. That is unusual for an application, and the composition explains why more than the count does.

Three are containers: the main Dockerfile, one for a different CPU architecture and one for a proxy role. Nine are compose files, covering a development setup, a local setup, a production setup, a small-NAS setup, a test setup, a single-command variant and two more for specific transports.

Five are planning documents: an architecture document, a plan, a second plan whose filename ends in a number, a list of outstanding work and a release notes file. Two of those five exist alongside a readme that documents none of them.

Two files at the root have names that read like scratch output: a log file and a message file. They are committed.

Then the tooling that explains the size. There is a lint baseline file, a generated public-key script for push notifications, a telemetry copy script, an admin check, an admin reset, an HTML embed file, a proxy start script, an export manifest, a proxy configuration file, a virtual-host configuration file, a container-recipes directory, a protobuf directory, a bridge directory and a desktop directory.

Two agent-configuration directories also sit at the root, plus a development-container configuration, a gitignore template, an environment example, an environment example for production and a submodules file.

None of this is wrong. It is what a project looks like when it ships a dozen deployment shapes and runs its own quality gates. But it means a reader who opens the root is looking at a working inventory rather than a curated one, and the readme accounts for none of it.

Nine compose files and three Dockerfiles for three named mesh sources

The project describes itself as monitoring three things: one mesh radio protocol, a second mesh stack, and a message broker.

The root contains two compose files for transports that are not in that list. One targets a short-range wireless transport and one targets a different mesh protocol entirely.

So the deployment matrix is wider than the feature headline. Two of the nine compose files are for protocols a reader would not learn about from the readme, and the compose files for the three named sources are not distinguished from them by name.

That matters because each compose file is a complete deployment decision: which ports, which database, which environment, which restart policy. Nine of them is nine configurations to keep in step with one application, and the readme documents exactly one of them, plus a Helm chart.

The Helm path is a good one to note. You add a chart repository whose address is served from the project's documentation domain, then install from it, so the charts and the documentation are the same deployment. There is a documented local alternative that installs from a checkout instead.

Two naming conventions meet in that Helm example. The chart's values use lower camel case for the node address and the TLS flag, while the environment variables the application reads are upper case with underscores. So the same two settings are spelled differently depending on whether you deploy by chart or by environment, and the environment example file does not list a TLS entry at all.

One of the three headline sources also lost its environment configuration entirely. The environment example says the legacy bootstrap variables for the second mesh stack were removed in a recent version and that sources of that kind are now added from the dashboard instead.

The lint setup is a ratchet with a recorded baseline and five bespoke checks

The quality gates in the manifest are the most interesting thing in this repository, and they are not a single command.

There is an ordinary lint script that runs the checker over the tree. Then there is a continuous-integration variant that chains four things: a set of tests for the checker's own custom rules, a script that checks user-interface glyphs per locale, a script that checks that no symbolic links are tracked, and a ratchet script.

The ratchet is the notable one. There is a second script that runs the same ratchet with an update flag, and a baseline file at the repository root.

So existing violations are recorded in that baseline, and the gate fails only on new ones. The update script rewrites the baseline. This is a technique for adopting strict linting on a large existing codebase without blocking every pull request, and having it in a repository of this size is a sign the maintainers expect to keep it.

Two of the four checks are specific enough to be worth naming on their own. One checks that no symbolic links are tracked in git, which matters on Windows checkouts and in container builds. One checks user-interface glyphs per locale, which is what a project with a translation platform and a dark theme needs.

Alongside those, two more scripts sit outside the lint chain: one checks that runtime imports resolve, and one enforces a bundle-size ceiling.

And the quick start is itself a test. There is a script that runs a shell file of that name, so the two-minute install is covered by continuous integration rather than trusted.

The production image build is shaped by a dev-only screenshot tool crashing under emulation

The container file has a comment block longer than most of its instructions, and it is all about one dev dependency.

The build stage pins a specific Node version on a specific Alpine release and installs a compiler toolchain and Python, because two native dependencies ship prebuilt binaries but one of them does not have a prebuilt for every target, notably Alpine on arm, so the compiler has to be able to build it from source.

Then the screenshot tool. Its install step downloads a Chrome binary. This image is built for arm64 under emulation, where that download step crashes with an illegal-instruction signal and takes the whole build down with it. The tool is a development dependency used by two screenshot helpers, and neither the runtime image nor the build needs a browser.

So an environment variable is set to stop that download, and a long comment explains why the configuration-file route no longer works: the tool's skip setting is in the repository's npm configuration file, but npm now reports it as an unknown project setting and stops forwarding it, so the tool never sees it and downloads anyway.

That means there is a committed configuration file at the root whose only notable setting is now inert, and a comment in a container file explaining that it is inert.

Two more choices in the same file. The build uses the plain install command instead of the reproducible one, with a comment citing an optional-dependency bug. And a legacy peer-dependency flag is passed for test-framework conflicts, in a production build.

A dev-only screenshot helper has shaped three decisions in the file that produces the shipping image.

Proxy authentication has three requirements and one of them defaults to off

The single-sign-on section is the most carefully written documentation in this readme, and it opens by saying what proxy authentication is not: it is not a substitute for the network being closed.

Three requirements are listed. The application must not be directly reachable, so use container networks, firewall rules or a VPN. The proxy trust setting must be configured. And the proxy must validate authentication before forwarding.

Then a versioned warning. Since a recent version, the proxy trust setting defaults to off, and you must set it whenever the application runs behind any reverse proxy. The stated consequence of getting it wrong is specific and worth repeating: client address resolution, rate limiting and audit logs all show the proxy's address instead of the client's.

That default is the right default and the sentence tells you exactly what breaks, which is the combination that makes a warning useful.

The section then handles the proxy-specific failure that is hardest to debug. One of the supported proxies issues application tokens that contain only a subset of the identity, and custom claims appear only if the identity provider integration is configured to include them. If the configured groups claim is absent from the header, the application sees empty groups and group-based admin never triggers at all.

The advice is to decode a real token from your own deployment and treat that as the truth, because the vendor's examples may show a different layout than your tenant produces. And there is a documented fallback: an operator email allowlist, matched case-insensitively, which works even when the token omits custom claims.

Two more honest notes sit alongside. The groups claim is normalised across three shapes, because one identity provider emits role objects instead of strings. And email uniqueness is not enforced in the database schema, so if two users share an address the first match wins.

TRUST_PROXY is off by default, the default password is changeme, and both are stated plainly

Pulling the security-relevant defaults together, because they are what a reader should take away.

There is a documented default login of an administrator account with a placeholder password and an instruction to change it. There is a documented proxy trust setting that defaults to off, with the consequence spelled out. There is a proxy authentication switch that defaults to off and a separate auto-provision switch that also defaults to off. There is a setting for a virtual node server that defaults to off and whose documentation carries an explicit warning that enabling it reduces security by allowing clients to send administrative commands.

And there is a documented absence: email uniqueness is not enforced, so two accounts sharing an address collapse to the first match.

Set against that, the application is designed to be exposed. It publishes a dashboard port and a broker port, it supports being put behind an authenticated proxy with group-based administration, and it ships nine deployment configurations plus a chart.

The reconnect behaviour is worth one more note because it is the kind of tuning knob that matters on a flaky link. The environment example documents an exponential backoff for reconnects, with an initial delay and a maximum, described as doubling per attempt and capped, and it tells you that setting the two to the same value gives a fixed delay instead. There is also a documented knob for the gap between consecutive configuration requests, with the advice to raise it if the node shows queue overflow during configuration loading.

That last one is the kind of comment that tells you somebody has watched this fail in the field, which is the best evidence in the whole repository that the rest of the documentation can be trusted.

Editorial conclusion

MeshMonitor is the most operationally serious project in this set and its documentation is unusually honest about failure modes, including the ones that would embarrass a vendor. Read the proxy authentication section before you put it behind anything, because the three requirements it lists are not optional and one of them changed default in a recent version. And do not treat the two-minute install as equivalent to the shipped compose file, since it drops a port and a CORS setting that the project's own file calls required.

Frequently asked questions

How do I set up MeshMonitor?

Create a compose file with the published image, a data volume and a node address, then start it and open the dashboard port. The readme calls it a sixty-second install. A Helm chart is also published from a chart repository served at the documentation domain, and a local checkout install is documented.

What is the default password for MeshMonitor?

The default login is an administrator account with the password changeme, and the readme tells you to change it after the first login. The repository root also contains a script that checks the admin account and one that resets it.

what is mesh monitor

In this project it is a React, TypeScript and Node web application that monitors off-grid mesh networks from one dashboard, covering a mesh radio protocol, a second mesh stack and a message broker, with SQLite, PostgreSQL and MySQL support and a dark theme.

Official sources

  1. Official documentation
  2. Official README
  3. Project repository
  4. Release notes
Add this badge to your README

If you maintain this project, the badge below links readers to this analysis and shows its maintenance status from the daily GitHub snapshot. Paste the markdown into your README; add ?metric=license or ?metric=stars to the image URL for a different field.

Add this badge to your README

markdown
[![Hysen Labs](https://hysenlabs.com/badge/yeraze-meshmonitor.svg)](https://hysenlabs.com/projects/yeraze-meshmonitor)

Star history chart for your README

markdown
[![Star history](https://hysenlabs.com/chart/yeraze-meshmonitor.svg)](https://hysenlabs.com/projects/yeraze-meshmonitor)

Was this useful?