Linux Agent
netignite-agent connects a Linux machine to your NetIgnite server. It has two modes:
- Host mode (always on): the dashboard sees whether this machine is online and can shut it down or reboot it.
- Wake-on-LAN mode (optional): the agent also wakes other devices in its network, checks whether they're online and logs in to them over SSH to shut them down or reboot them. That's what the ESP32 agent does, on a machine you already run: a Raspberry Pi, a NAS or a home server.
The agent is a single binary that runs as a systemd service under its own unprivileged user. It talks to the server over one outgoing WebSocket; nothing listens on the machine. Source and releases: NetIgnite-project/Agent-Linux.
Requirements
- Linux with systemd, on a 64-bit x86 or ARM CPU.
- polkit, for shutdown and reboot (
apt install polkitdon Debian and Ubuntu,dnf install polkiton Fedora). Without it, the agent runs, but shutdown and reboot fail. - Wake-on-LAN mode:
ping(iputils or BusyBox) andip(iproute2). curlandsha256sumfor the install script.
| Binary | For |
|---|---|
netignite-agent-linux-x64 | x86-64 CPUs with AVX2 (about 2013 and newer) |
netignite-agent-linux-x64-baseline | Any x86-64 CPU |
netignite-agent-linux-arm64 | 64-bit ARM, for example a Raspberry Pi 3, 4 or 5 with a 64-bit OS |
Install
- In the dashboard, create an agent of the kind Linux agent (Agents → Add agent).
- On its page, click Create setup command.
- Run the command on the Linux machine within 15 minutes:
curl -fsSL https://netignite.example.com/install/linux.sh | sudo sh -s -- netignite_enroll_…
The script, served by your NetIgnite server:
- checks that it runs on Linux as root with
curl,sha256sumand systemd, - picks the binary for the CPU:
arm64,x64if the CPU has AVX2,x64-baselineotherwise, - downloads it and
SHA256SUMSfrom the GitHub releases and checks the checksum, - pairs the agent with the server using the token,
- installs the systemd service and starts it.
The agent shows up as online on its page. Then:
- To control this machine, open (or add) the device for it, choose the agent under Linux agent on the device, and choose the status check Linux agent on the device. The device gets Shut down and Reboot.
- To wake other devices, turn on Wake-on-LAN mode and choose the agent as the Agent of those devices.
By default, the script installs the newest stable release (a pre-release only while there is no
stable one). The server's admin can pin a release with NETIGNITE_LINUX_AGENT_VERSION or use
another repository with NETIGNITE_LINUX_AGENT_REPO (see
Configuration).
On the machine, the variables NETIGNITE_AGENT_VERSION (a release tag) and
NETIGNITE_AGENT_BASE_URL (a mirror with the release files) override that; pass them through
sudo env:
curl -fsSL https://netignite.example.com/install/linux.sh | sudo env NETIGNITE_AGENT_VERSION=v1.0.0 sh -s -- netignite_enroll_…
Manual install
Without the script, or if the machine reaches the server under another address than the dashboard's:
arch=x64 # or x64-baseline, arm64
base=https://github.com/NetIgnite-project/Agent-Linux/releases/latest/download
curl -fsSLO "$base/netignite-agent-linux-$arch"
curl -fsSLO "$base/SHA256SUMS"
sha256sum --check --ignore-missing SHA256SUMS
chmod +x "netignite-agent-linux-$arch"
sudo ./netignite-agent-linux-$arch pair https://netignite.example.com netignite_enroll_…
sudo ./netignite-agent-linux-$arch install
releases/latest skips pre-releases. install copies the binary to
/usr/local/bin/netignite-agent.
Updating
Run the install script again without a token. It downloads the current release and reinstalls the service with the existing pairing:
curl -fsSL https://netignite.example.com/install/linux.sh | sudo sh
Pair
sudo netignite-agent pair <server-url> <enrollment-token> [--wol] [--config <path>]
- The agent generates its own secret (32 random bytes), sends it with the token to
POST <server>/api/v1/agents/enrolland writes the result to/etc/netignite/agent.json(mode0600). Neither the secret nor the token is printed. <server-url>is the server's address, for examplehttps://netignite.example.comorhttp://192.168.1.10:18232. A missing scheme meanshttps://.- Pairing again with a new token replaces the credential. The server disconnects the old one, and an installed service is restarted with the new one.
- A token of an ESP32 agent is refused and stays valid for that ESP32. Create a Linux agent for this machine instead.
--wolturns on Wake-on-LAN mode. Without it, pairing again keeps the previous mode.
The config file looks like this:
{
"server": "https://netignite.example.com",
"agent_id": 3,
"token_id": "…",
"secret": "…",
"wol": { "enabled": false }
}
Host mode
In host mode, the agent announces the capabilities host.status and host.control. The server can
then:
- show the machine as online while the agent is connected (status check Linux agent on the device),
- send
HOST_CONTROLwithshutdownorreboot. The agent first asks systemd-logind whether it may (CanPowerOff/CanReboot); if not (polkit rule missing, or a block inhibitor such as a running package upgrade), it answers with the reason, which the dashboard shows. Otherwise it answers, waits about a second and runssystemctl --no-ask-password powerofforsystemctl --no-ask-password reboot.
Nothing else: the server can't run commands, read files or change the configuration. If
systemctl still fails after the answer, the error is in the agent's journal.
Wake-on-LAN mode
sudo netignite-agent wol-mode on # or: pair --wol
sudo netignite-agent wol-mode off
wol-mode updates the config and the installed service, and restarts it. In this mode, the agent
also announces wake, status.link_local, status.ip, status.host, status.tcp and ssh:
- Wake: a magic packet over UDP to
255.255.255.255and each network interface's broadcast address, three times, 100 ms apart. - Status: the device is online if it answers a ping (
ping -c 1 -W 1) or the TCP port (a refused connection counts too). For the MAC check, the agent first looks at the neighbor table (ip neigh): a reachable entry for the MAC address counts as online. Otherwise it pings the IPv6 link-local address derived from the MAC address and the addresses the neighbor table knows for it. Every check answers within 4.5 seconds. - SSH: logins to devices in the network for shutdown and reboot over SSH.
To test Wake-on-LAN from the machine itself:
netignite-agent wol AA:BB:CC:DD:EE:FF --port 9
The systemd service
install needs root and a paired config. It:
- creates the system user
netignite(no home directory, no login shell), - copies the binary to
/usr/local/bin/netignite-agent, - makes the config readable for the service:
/etc/netigniteowned byroot:netignitewith mode0750,agent.jsonowned bynetignitewith mode0600, - writes
/etc/systemd/system/netignite-agent.service, - writes the polkit rule
/etc/polkit-1/rules.d/50-netignite-agent.rules(plus a.pklafile in/etc/polkit-1/localauthority/50-local.d/on polkit older than 0.106, for example Debian 11), - runs
systemctl daemon-reload,enableandrestart.
sudo netignite-agent install --dry-run prints every step and the files' contents without changing
anything. The unit for host mode (comments left out):
[Unit]
Description=NetIgnite Agent
Documentation=https://github.com/NetIgnite-project/Agent-Linux
Wants=network-online.target
After=network-online.target
[Service]
Type=simple
User=netignite
Group=netignite
ExecStart=/usr/local/bin/netignite-agent run --config /etc/netignite/agent.json
Restart=always
RestartSec=5
RestartPreventExitStatus=78
TimeoutStopSec=10
NoNewPrivileges=yes
ProtectSystem=strict
ProtectHome=yes
PrivateTmp=yes
PrivateDevices=yes
ReadOnlyPaths=/etc/netignite
ProtectKernelTunables=yes
ProtectKernelModules=yes
ProtectKernelLogs=yes
ProtectControlGroups=yes
ProtectClock=yes
ProtectHostname=yes
RestrictNamespaces=yes
RestrictRealtime=yes
RestrictSUIDSGID=yes
LockPersonality=yes
SystemCallArchitectures=native
UMask=0077
RestrictAddressFamilies=AF_UNIX AF_INET AF_INET6 AF_NETLINK
CapabilityBoundingSet=
[Install]
WantedBy=multi-user.target
In Wake-on-LAN mode, the last line is replaced by CapabilityBoundingSet=CAP_NET_RAW and
AmbientCapabilities=CAP_NET_RAW, which ping needs. Use systemctl edit netignite-agent for local
changes; install and wol-mode overwrite the unit file.
polkit
The rule lets the user netignite, and nobody else, use exactly the logind actions behind
systemctl poweroff and systemctl reboot:
polkit.addRule(function (action, subject) {
var allowed = [
"org.freedesktop.login1.power-off",
"org.freedesktop.login1.power-off-multiple-sessions",
"org.freedesktop.login1.reboot",
"org.freedesktop.login1.reboot-multiple-sessions"
];
if (subject.user == "netignite" && allowed.indexOf(action.id) >= 0) {
return polkit.Result.YES;
}
});
The *-multiple-sessions actions apply when other users are logged in, for example over SSH. The
*-ignore-inhibit actions aren't granted, so a block inhibitor (a running package upgrade, for
example) still stops a remote shutdown. systemctl asks logind over D-Bus, and logind asks polkit;
no setuid helper is involved, so NoNewPrivileges doesn't get in the way.
Commands
| Command | What it does |
|---|---|
pair <server-url> <token> | Registers with the server and writes the config (--wol, --config). |
install | Sets up and starts the systemd service (--config, --dry-run). |
uninstall | Removes the service (--purge, --config, --dry-run). |
run | Runs the agent in the foreground; this is what the service runs (--wol, --config). |
status | Shows the config, the server, the agent ID, the service state and whether the server and the credential work. Never shows the secret. |
wol-mode on|off | Turns Wake-on-LAN mode on or off (--config). |
wol <mac> | Sends a magic packet from this machine (--port, default 9). |
version | Prints the version. |
Global flags go before the command, for example netignite-agent --log-level debug run. The
default config path is /etc/netignite/agent.json.
Exit codes: 0 success, 1 error, 78 the server rejected the credential. The service isn't
restarted after 78; pair again.
sudo netignite-agent status
journalctl -u netignite-agent -f
Connection
The agent keeps one WebSocket to <server>/ws/agent (wss:// for https:// servers) and speaks
the agent protocol. Its HELLO reports the version, the capabilities and,
for the dashboard, the host name, OS, kernel, architecture, uptime, IP addresses and whether
Wake-on-LAN mode is on.
- It reconnects after 5 seconds, doubling the wait up to 60 seconds. If the server sends nothing for 100 seconds (it pings every 30 seconds), the agent drops the connection and reconnects.
- It stops for good and exits with
78when the server rejects the credential (HTTP 401), revokes it (close code4003, for example after pairing again or Revoke credential) or deletes the agent (4004). - If another connection with the same credential takes over (
4000), it waits 60 seconds before reconnecting, so two copies of the agent don't keep replacing each other.
Uninstall
sudo netignite-agent uninstall # keeps /etc/netignite/agent.json (root-only again)
sudo netignite-agent uninstall --purge # also deletes the config with the credential
This stops and disables the service and removes the unit, the polkit rule, the user netignite
and /usr/local/bin/netignite-agent. --dry-run shows the steps. Delete the agent in the dashboard
too.
Security
- Fixed actions only. The server can ask for
PING,HOST_CONTROL(shutdownorreboot) and, in Wake-on-LAN mode,WAKE,STATUS,SSH_CHECKandSSH_EXEC(one of four fixed commands on another device). Every parameter is validated; commands run without a shell, and only IP addresses reachping. There's no remote shell, no file access and no configuration change from the server. - The secret is generated on the machine and only leaves it in the
Authorizationheader. The server stores only a hash. It's in/etc/netignite/agent.jsonwith mode0600and never printed, not even bystatus. Use anhttps://server address outside your LAN. - The service runs as the unprivileged user
netignitewith the hardening options above, without capabilities in host mode and with onlyCAP_NET_RAWin Wake-on-LAN mode. - SSH logins for other devices arrive with each request and are only kept in memory for that login; the agent never writes or logs them. See SSH.
- The binary doesn't load
.envorbunfig.tomlfrom the working directory, so a stray file there can't change howpairorinstallbehave when run as root.
Building from source
The agent is written in TypeScript and compiled with Bun into single binaries.
git clone https://github.com/NetIgnite-project/Agent-Linux.git
cd Agent-Linux
bun install
bun test
bun run compile all --no-version-tag # build/bin/netignite-agent-linux-{x64,x64-baseline,arm64}
Releases are built by the repository's release workflow when a tag v<version> is pushed; it
attaches the three binaries and SHA256SUMS. Versions with a suffix, such as 1.0.0-beta.1, are
published as pre-releases.