Architecture

How the panel is put together, from one Go binary serving a React SPA to the four ways it can reach a router.

Last updated Aug 17, 2026View as Markdown

Overview

Nasnet Panel is one process. A Go service (Echo v4) exposes a JSON API and serves the React single-page app from the same port, because the compiled frontend is embedded into the binary with go:embed. There is no separate web server, no database, and no agent installed on the routers.

That shape is deliberate. The panel is meant to run on a MikroTik with 30 MB of RAM to spare, and every extra moving part would have to fit in that budget too.

The pieces

Piece What it does
React SPA The operator interface. Talks JSON to its own origin.
Go API (Echo v4) Serves the SPA, exposes the API, and proxies every router call.
Embedded assets The built frontend, compiled into the binary via go:embed.
Subnet scanner Sweeps a subnet for MikroTik devices and identifies services on common ports.
Batch executor Runs sequences of RouterOS commands with progress, dry-run, and rollback on failure.

How it reaches a router

The backend speaks four protocols and falls back automatically, in this order:

  1. REST API, the RouterOS v7 HTTP interface. Preferred.
  2. RouterOS API, the native binary protocol on 8728, or 8729 with TLS.
  3. SSH on port 22.
  4. Telnet as a last resort, for devices where nothing else is open.

Fallback is per-router and automatic, so a fleet where one device only answers on SSH and another has the REST API enabled needs no special handling. Nothing is installed on the router itself; every operation is a command sent over one of these four transports.

Batching and rollback

Anything that changes more than one setting at a time goes through the batch executor rather than being fired off command by command. A batch reports progress as it runs, can be dry-run first to show exactly what would be sent, and rolls back the steps it already applied if a later one fails. This is what sits under the Easy Config wizard, which is a batch with a friendly face.

Trust boundaries

Worth being precise about where things run, because it is easy to assume otherwise:

  • Router credentials are held by the Go backend for the duration of a session and used to open connections to the router. They are not sent to the browser.
  • The browser only ever talks to the panel, never directly to a router.
  • Crash reports come from the browser, not the router. The MikroTik never connects to an error-reporting service. Reports carry the error, stack trace, app version, and browser and OS name; IP addresses are stripped before sending, and the whole thing can be turned off per browser from the Diagnostics page.

Deployment shapes

Shape What it looks like
On the router A RouterOS container on veth1 at 192.168.50.2/24, reached through a dst-nat rule from the LAN port.
On a LAN server A plain Docker container, usually with host networking so it can see the routers.
From source Frontend dev server on 3000, backend on 8080, with API calls proxied across.

The production image is built on busybox with musl, running a compressed Go binary with GOMAXPROCS=1 and a /health endpoint behind the container healthcheck. Images are published multi-arch for linux/amd64, linux/arm64 and linux/arm/v7.