Architecture
WG Free Mesh consists of the web console, backend, database, Go client, EMQX, and Docker gateway.
Browser Console
-> Gateway
-> Frontend static files
-> FastAPI backend
-> SQLAlchemy repository
-> SQLite / PostgreSQL
-> EMQX management API
-> MCP server
-> EMQX MQTT ports
wfm-agent
-> Backend bind API
-> EMQX MQTT
-> wg / awg / wg-quick / awg-quickComponents
Web Console
The frontend handles page structure, user input, API calls, state display, and interaction feedback. It does not duplicate backend business rules.
FastAPI Backend
The backend owns business rules. Configs, nodes, mesh pairs, port forwarding, snapshots, MCP, client binding, MQTT authorization, and system status are driven by application data in the database.
Database
The database is the business source of truth. SQLite and PostgreSQL are both supported through SQLAlchemy. Schema changes must go through Alembic migrations.
EMQX
EMQX is the MQTT transport layer. Node accounts, passwords, authorization rules, and connection state are synchronized by the backend from the database.
Go Client
The client consists of wfm-agent and wfmctl. wfm-agent runs as a system service. wfmctl installs, binds, checks status, reads logs, starts, stops, and uninstalls the service.
Docker Gateway
Docker deployment provides one web entrypoint through the gateway. Production HTTPS should be terminated by Nginx, Caddy, or an external gateway.
Control Plane and Data Plane
WFM manages the WireGuard / AmneziaWG control plane. It does not proxy tunnel traffic.
Control plane:
- Browser console.
- REST API calls to the backend.
- SSE events from backend to console.
- MQTT commands from backend to dynamic clients through EMQX.
- MQTT heartbeat, ACK, runtime status, and logs from clients.
- MCP calls through
/mcp.
Data plane:
- WireGuard / AmneziaWG UDP tunnels between nodes.
- User traffic inside those tunnels.
- Port forwarding rules applied locally on the destination node through lifecycle hooks.
The backend is not in the mesh data path. If the backend is offline, already-running tunnels may keep running with their local client config, but the console cannot push new config or commands.
Entrypoints
| Entrypoint | Consumer | Notes |
|---|---|---|
| Web/API/SSE/MCP gateway | Browser, AI clients, external HTTP callers | Docker deployment exposes these through the gateway. |
| MQTT public listener | wfm-agent | Clients connect to EMQX. Port and TLS depend on deployment and settings. |
| WG/AWG UDP | Mesh nodes | Direct node-to-node data traffic; not proxied by WFM. |
Production deployments should put Web/API/SSE/MCP behind the same HTTPS reverse proxy entrypoint. MQTT may be exposed by the gateway on separate ports.
Client Channel
A dynamic node uses two channels:
- One-shot HTTP bind:
wfmctl bindcalls/api/client/bindwith a bind token. - Long-running MQTT control channel:
wfm-agentconnects to EMQX using credentials returned by bind.
After bind, the backend stores MQTT credentials in the database and synchronizes them to EMQX. The local client profile stores only connection data. The backend includes the current tunnel protocol and config in each control, detect, and config push payload.
Realtime Channel
The console uses SSE instead of WebSocket because writes already go through REST, while realtime mainly needs server-to-browser refresh signals.
SSE events are refresh hints. The frontend should use event type and scope to refetch the related REST projection instead of reconstructing business state from event payloads.
EMQX Sync Model
EMQX is a runtime projection, not the business source of truth.
The backend:
- Generates node MQTT username/password/client_id.
- Stores them in the database.
- Creates or updates EMQX users through the management API.
- Serves EMQX AuthZ HTTP callbacks.
- Rebuilds EMQX node users after backend startup, EMQX recovery, and snapshot restore.
If EMQX is temporarily unavailable, the backend should still start and non-MQTT features should keep working. Client control features should report unavailable instead of bringing down the whole application.
Snapshot Model
Snapshots are application-level snapshots, not raw database file copies.
They include application data except the administrator password, including configs, nodes, mesh links, port forwards, system settings, MCP tokens, MCP audit records, client MQTT credentials, snapshot metadata, and WireGuard directory data.
After restore, historical online state is not trusted. The backend clears runtime state, rebuilds EMQX users from restored client credentials, and uses detect to confirm endpoint state again.
Failure Behavior
| Failure | Expected behavior |
|---|---|
| EMQX unavailable | Backend can start; MQTT control is unavailable; database remains the source of truth. |
| Client offline | Control commands cannot complete; UI shows offline or dropped; runtime state waits for client report. |
| SSE disconnected | Frontend reconnects and may refetch system status. |
| Database unavailable | Backend startup fails after retry; it must not fabricate business state. |
| Gateway unavailable | External Web/API/SSE/MCP access fails even if internal services are running. |
Write Flow
- The frontend calls a backend API.
- The backend validates and writes to the database.
- The backend publishes SSE events.
- If a client action is needed, the backend sends MQTT commands.
- Client ACKs update runtime state and control logs.
Design Decisions
- The backend should still start when EMQX is temporarily unavailable.
- Snapshots are application-level data, not SQLite files or PostgreSQL dumps.
- MCP and Web APIs reuse the same business layer.
- Docker is the recommended deployment path because it coordinates backend, frontend, EMQX, certificates, and gateway behavior.
Continue Reading
- Source directories and ownership boundaries: Project Structure.
- Backend services and repositories: Backend.
- Migrations, repositories, and snapshots: Database.
- Dynamic client communication: MQTT Protocol and Client Lifecycle.
- Browser realtime refresh: Events and Realtime Reference.
- Deployment, environment variables, and HTTPS reverse proxy: Docker Deploy, Environment, Reverse Proxy.
