Connecting Routers Behind NAT: Fleetd Agent Enrollment, Approval and Reconnection

How Fleetd v0.3.0 connects Linux and OpenWrt agents behind NAT: outbound WebSockets, pinned keys, fingerprint approval, retry policies and device removal.

Connecting a cloud server to a management dashboard is usually straightforward: install the program on a reachable machine, configure an address and check the connection.

A home router adds another layer. It may have no public IPv4 address, with a modem and the ISP’s network in front of it. Port forwarding, dynamic DNS or a jump host can turn the management entry point itself into another maintenance task.

In the Fleetd introduction, I mentioned that agents initiate their connections. This article explains the direction of that connection, how a new device is approved and what happens after an outage.

The discussion follows Fleetd v0.3.0. It connects your own servers and routers to a dashboard. It is not a general-purpose tunneling service and does not automatically expose the router’s entire LAN.

Reverse the connection direction

Remote management often starts with the question: how does the dashboard find my home router?

Fleetd lets the router’s agent find the server instead. The server offers a reachable address; the agent establishes a WebSocket connection and uses it for monitoring reports and subsequent requests.

Linux agents and agents behind NAT both connect outward to fleetd-server. The server stores data in PostgreSQL, and the administrator accesses its web interface.

Managed machines need no dedicated inbound listening port for Fleetd. The server does not have to discover every router’s current public address before initiating contact.

There is still a prerequisite: the agent must be able to reach the server. DNS, outbound rules, proxies and network quality all matter. The server can use a public domain or a private network reachable by the agents. An existing WireGuard network can provide that reachability too.

Working behind NAT means changing who initiates the connection. It neither bypasses outbound restrictions nor makes an otherwise unreachable server accessible.

A working web page proves only one path

You may be able to sign into the dashboard while agents fail to connect. Those are different paths: the browser uses the admin pages and API, while an agent connects to its configured WebSocket endpoint, for example:

wss://fleetd.example.com/agent/ws

Replace the example domain with your own address. The reverse proxy must support WebSocket upgrades and avoid closing long-lived connections prematurely.

If the homepage works but WebSocket forwarding is missing, reinstalling the agent is unlikely to help. Check its address, proxy logs and handshake errors first.

Inside WebSocket, Fleetd establishes a Noise-encrypted session between agent and server. Agents pin a server public key: reaching an address is not enough to trust any server behind it.

HTTPS certificate validation and the pinned Noise identity serve different purposes. A wrong key, or an accidentally changed server identity during migration, can prevent connection. Production deployments should still use HTTPS. Noise does not protect browser access by itself, and its endpoints include the server, which can read the monitoring data it receives.

Prepare agents before copying an installer command

The previous Docker Compose example started the server and PostgreSQL. It did not automatically supply signed agent release bundles for installation.

For ongoing use, follow the deployment guide to create your release key, build and upload a bundle matching the target architecture, then use the dashboard’s installation command. The v0.3.0 binaries target Linux amd64 and arm64; check the router’s architecture rather than assuming all OpenWrt devices match.

For the first machine, I recommend monitor permission. Validate connectivity and reporting before deciding whether remote execution is necessary. An installer command has this form:

curl -fsSL https://fleetd.example.com/install.sh | sh -s -- --permission monitor

This is an example, not a real deployment address. Obtain the command from your own dashboard and confirm its source before executing it. Installation requires elevated privileges. Trust in the initial installer is part of the process; later signatures do not retroactively authenticate the first script you downloaded.

The installer handles systemd or OpenWrt’s procd, writes configuration and installs the agent as a service. Several keys appear in that configuration, and they answer different questions:

Information Question it answers
Server public key Am I connecting to the expected Fleetd server?
Agent identity key and fingerprint Which agent is requesting enrollment?
Command-signing public key Did a trusted signer authorize this command?
Release public key Did a trusted publisher sign this agent update?

Connection failures and command rejections can belong to different checks. Replacing an arbitrary key is not a general fix.

Pending approval is an intentional stage

On startup, the agent loads or creates its identity key. An unfamiliar identity that completes the relevant handshake is registered as pending.

At this stage the server retains registration information such as hostname, source address and public key. It has not entered normal monitoring and command processing. A pending row without resource graphs is therefore not necessarily a collector failure.

Read the fingerprint from an installation terminal or another connection you already trust, then compare it with the dashboard. For an installed agent with the correct configuration path:

fleetd-agent -config /etc/fleetd/agent.yaml fingerprint

Approve only after they match. Do not identify an unfamiliar registration solely by the hostname it supplies.

IP addresses are clues too, not identities. Several devices may share an exit address; home addresses may change; reverse proxy configuration can affect the recorded source. Names and addresses help humans recognize machines, but the expected agent identity needs verification.

Approval and command permissions are separate. An approved monitor-only machine remains monitor-only. Remote actions still need valid signatures and local authorization; approval does not open a root terminal on every machine.

Why approval is not necessarily instant

In v0.3.0, an agent that is pending retries at a fixed interval of about one minute. After approval it normally waits for the next connection before entering a regular session and reporting.

The approval button does not immediately transform the old pending connection. If data is absent a few seconds later, check the agent logs before deleting or reinstalling it.

That minute is not an availability guarantee. DNS, connectivity and handshake failures may still block enrollment. Distinguish waiting for another attempt from an attempt that actually failed.

Ordinary disconnections follow another retry policy

After network errors, agents use exponential backoff with random jitter instead of retrying continuously. This reduces synchronized reconnect bursts when a server recovers.

The backoff base starts at one second and grows to 60 seconds. Actual waits include additional randomness, so “guaranteed to reconnect within 60 seconds” would be inaccurate. A session lasting more than a minute resets the base to a short wait when it ends.

The server also sends keepalive messages. A prolonged lack of incoming progress ends the session and leads to reconnection. These mechanisms recover connections; they do not prove that every remote action resumes.

An online machine does not prove a previous command succeeded or that its terminal task continued. Software upgrades, network changes and service restarts may themselves break the connection. Check the actual outcome before repeating an action just because its completion message was lost.

The commands-and-terminal article will discuss task lifetimes. For enrollment, keep network-session recovery separate from operation recovery.

Renaming, changing addresses and reinstalling are different

Agent identity is based on its key, not its hostname or current IP. Reconnecting with the same identity from a different address differs from registering with a newly generated key.

If reinstallation removes the old identity key, the same hostname may appear as a new agent and require verification again. Conversely, cloning an enrolled machine’s system may copy its key to another device.

Two machines sharing one identity cannot be treated as independent agents. The current server cancels an older connection when a new connection arrives for the same registered machine, so identity duplication can also look like repeated disconnections.

Do not distribute an enrolled agent’s private key in a system template. Ordinary restarts should preserve identity; newly deployed machines should each get a distinct one. Copying the entire configuration directory cannot safely serve both purposes.

Deleting a machine does not prevent its return

Deleting a machine clears its dashboard record and history. If its agent continues running, it may reconnect and appear as pending again. The server has forgotten approval, but the device has not stopped applying.

Use rename for a display-name change. To stop management, stop and uninstall the agent following the guide. To reject an identity, use rejection: its public key is blocked from admission until unblocked.

A block entry applies to a key. Generating a new key creates a different identity, which still needs approval; this is not a permanent hardware-level ban.

The current implementation caps pending machines at 50. That bounds the registration queue, not every possible attack. Network exposure, entry-point defenses and administrator accounts still need suitable protection.

Diagnose the stage, not just the symptom

Symptom Check first
No running service after installation Architecture, downloads, installation errors and systemd/procd status
No pending entry Endpoint, DNS, outbound access, WebSocket forwarding and server key
Pending entry but no metrics Fingerprint verification, approval and retry timing
Still offline after approval Latest handshake and whether an approved session was established
Online but commands refused Local permissions, trusted signing keys, target and validity period
Pending entry returns after deletion Whether the agent is still running and should be stopped or rejected

On systemd machines:

systemctl status fleetd-agent
journalctl -u fleetd-agent -n 80 --no-pager

On OpenWrt or iStoreOS:

/etc/init.d/fleetd-agent status
logread | grep fleetd

Output varies by system version. Identify the failing stage, and remove real addresses, domains and sensitive values before sharing logs. Never include identity private keys.

Keep the first enrollment small

Start with one test device using monitor permission. Verify its fingerprint through a trusted channel, approve it, observe fresh metrics, then arrange a controlled agent restart and confirm it returns with the same identity.

That makes enrollment easier to understand than immediately granting full access everywhere and issuing batch commands.

Fleetd separates reachability, server identity, agent identity and local authority. Keeping those decisions separate makes both troubleshooting and authorization clearer. Next, I will examine browser signing and why an agent verifies a request that already passed through the server.

Discussion

Share a question or your experience. Comments appear after moderation. Your email is never displayed publicly. Comment privacy

Loading comments…