Architecture
How the panel is put together, from one Go binary serving a React SPA to the four ways it can reach a router.
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:
- REST API, the RouterOS v7 HTTP interface. Preferred.
- RouterOS API, the native binary protocol on
8728, or8729with TLS. - SSH on port
22. - 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.