Noderax Agent is the Go-based node runtime for the platform. It enrolls a machine, opens the agent realtime socket, streams telemetry, claims tasks over HTTP long polling by default, and executes supported operations such as shell commands and package management.
- Enrollment-based node onboarding with approval tokens
- One-click bootstrap installer for Ubuntu and Debian
- Workspace-generated bootstrap tokens for the
Add nodeflow - Installer-side live progress reporting back to the control plane during bootstrap
- Background service support for Linux-based systems
- Dedicated
noderaxruntime user for the service and remote operations - Built-in CLI for install, start, stop, restart, status, and config updates
- Detached self-update command for official tagged agent releases
- Realtime Socket.IO session for agent auth, metrics, and lifecycle signaling
- HTTP long-poll task claiming as the primary execution path
- Interactive terminal session support over the agent realtime socket
- Heartbeat-based agent version, platform version, and kernel telemetry for fleet visibility
- Graceful cancellation with log-drain timeout handling
- Non-interactive execution environment with
PAGER=catand highCOLUMNS - PTY shell fallback modes for hosts where the default controlling-TTY start path is restricted
- Scheduled runs arrive as standard queued tasks, so no separate schedule runtime is required on the agent
- Persistent node identity storage
- Ubuntu and Debian hosts with
systemd - Manual source-based execution on other developer environments
The preferred onboarding path is from the web dashboard:
- Open
Nodesfor the target workspace. - Choose
Add node. - Fill in node metadata in step 1.
- Copy the generated install command from step 2.
curl -fsSL https://cdn.noderax.net/noderax-agent/install.sh | sudo bash -s -- --api-url https://api.example.com --bootstrap-token <token>The installer:
- checks and installs required packages
- creates the
noderaxsystem user - grants passwordless
sudoonly forapt-get install/remove/purge - grants passwordless
sudoto the dedicated/usr/local/libexec/noderax-agent-self-updatehelper used by fleet rollouts - downloads the correct prebuilt agent binary
- bootstraps the node with the provided token
- reports bootstrap progress back to the API so the web
Add nodemodal can update live - installs and starts the background service automatically
The bootstrap installer reports stage changes back to POST /api/v1/node-installs/progress while it runs.
Common stages:
installer_starteddependencies_installingdependencies_readyservice_user_readybinary_download_startedbinary_downloadedagent_bootstrappingservice_started
If any step fails, the installer reports failed so the web UI can stop waiting and show the error state.
Agent release assets can be published to Cloudflare R2 automatically by the GitHub Actions workflow at .github/workflows/agent-release.yml.
Expected R2 object layout:
noderax-agent/install.shnoderax-agent/releases/catalog.jsonnoderax-agent/releases/latest/noderax-agent-linux-amd64noderax-agent/releases/latest/noderax-agent-linux-arm64noderax-agent/releases/latest/SHA256SUMSnoderax-agent/releases/<version>/noderax-agent-linux-amd64noderax-agent/releases/<version>/noderax-agent-linux-arm64noderax-agent/releases/<version>/SHA256SUMSnoderax-agent/releases/<version>/release-manifest.json
Required GitHub secrets:
R2_ACCOUNT_IDR2_ACCESS_KEY_IDR2_SECRET_ACCESS_KEYR2_BUCKET
R2_BUCKET must be the plain bucket name only. Do not use a URL or custom domain.
Correct example:
R2_BUCKET=noderax-assets
Incorrect examples:
R2_BUCKET=https://cdn.noderax.netR2_BUCKET=https://<accountid>.r2.cloudflarestorage.com/noderax-assets
The workflow checks bucket existence before publishing. If you get NoSuchBucket, the most common reasons are:
R2_BUCKETis not the real bucket nameR2_ACCOUNT_IDbelongs to a different Cloudflare account- the access key pair belongs to a different account than the bucket
Trigger behavior:
- Pushes to
mainrefreshinstall.shand thelatestbinaries - Tags matching
agent-v*publish a versioned channel,release-manifest.json, and the sharedcatalog.json, then also refreshlatest - Manual runs can republish an existing tagged version through
workflow_dispatch
The workflow builds Linux amd64 and arm64 binaries, injects version metadata into the Go binary, and uploads the artifacts directly to R2 through the S3-compatible endpoint.
Official tagged release notes come from CHANGELOG.md. The release workflow turns that file into:
- the versioned CDN
release-manifest.json - the shared
releases/catalog.json - the GitHub Release body
- the GitHub Release
release-manifest.jsonasset used by API fallback
- Binary:
/opt/noderax-agent/noderax-agent - Symlink:
/usr/local/bin/noderax-agent - Config:
/etc/noderax-agent/config.json - State:
/var/lib/noderax-agent/agent_identity.json - Service:
/etc/systemd/system/noderax-agent.service - Runtime user:
noderax - Sudoers:
/etc/sudoers.d/noderax-agent
If you already have the binary on the target host, you can run the same bootstrap flow without the shell installer:
sudo ./noderax-agent install --non-interactive --api-url https://api.example.com --bootstrap-token <token>go build -o noderax-agent ./cmd/agentcp config.example.json config.jsonSet at least:
api_url
Leave enrollment_token empty. The enrollment command will populate it.
./noderax-agent enrollThe agent will:
- ask for the enrollment email
- call
POST /api/v1/enrollments/initiate - save the returned token
- poll
GET /api/v1/enrollments/{token} - persist the approved
nodeIdandagentToken
./noderax-agentUse a custom config path if needed:
NODERAX_CONFIG_FILE=/path/to/config.json ./noderax-agentsudo noderax-agent start
sudo noderax-agent stop
sudo noderax-agent restart
sudo noderax-agent statusPlatform-admin fleet rollouts do not use shell.exec. They dispatch the dedicated
agent.update task type, which hands off to the root-only helper below:
sudo /usr/local/libexec/noderax-agent-self-update --target-version 1.0.1 --target-id <rollout-target-id>The managed updater:
- fetches the official tagged release manifest from the CDN and falls back to the matching GitHub Release asset
- selects the correct Linux
amd64orarm64artifact - verifies the downloaded binary with
SHA256 - atomically replaces the managed binary and refreshes the symlink
- reports progress back to the API
- restarts
noderax-agent.service - leaves final success confirmation to the next heartbeat, which must report the target version
Show active config:
noderax-agent config showUpdate config values:
sudo noderax-agent config set api_url https://api.example.com
sudo noderax-agent config set task_timeout 30s
sudo noderax-agent config set metrics_interval 15s
sudo noderax-agent config set log_level debugSupported keys:
api_urlenrollment_tokennode_idagent_tokenheartbeat_intervalmetrics_intervaltask_poll_intervalrequest_timeouttask_timeoutshutdown_timeoutrealtime_enabledrealtime_ping_intervalrealtime_queue_sizerealtime_backoff_jitterrealtime_namespacerealtime_pathstate_filelog_level
The current default execution path is HTTP polling.
- The agent long-polls
POST /api/v1/agent/tasks/claim - A claimed task is acknowledged with
acceptedandstarted - Logs are appended through
POST /api/v1/agent/tasks/:taskId/logs - Completion is posted to
POST /api/v1/agent/tasks/:taskId/completed - Cancellation intent is checked through agent control polling
The agent realtime socket remains important for:
- agent authentication
- metrics streaming
- lifecycle support
- interactive terminal control and streaming
- optional compatibility with API-side realtime task dispatch when explicitly enabled
Fleet visibility also powers update completion. A fleet rollout only completes after heartbeat telemetry confirms that the restarted node is actually running the requested tagged agent version.
Typical realtime settings:
NODERAX_API_URL=https://<domain>
NODERAX_REALTIME_NAMESPACE=/agent-realtime
NODERAX_REALTIME_PATH=/socket.io/
NODERAX_REALTIME_PING_INTERVAL=2s
NODERAX_REALTIME_METRICS_INTERVAL=3sNotes:
- Auth is performed after socket connection with
agent.auth - Namespace and Engine.IO path are configured separately
- Startup performs a polling health-check against
/socket.io/before the full socket session is used
Common failure modes:
invalid URL inputtls/proxy handshake failurenamespace connect failureauth error
Interactive terminal sessions are not delivered through the HTTP task claim loop. They use the agent realtime socket directly.
Incoming control events:
terminal.startterminal.inputterminal.resizeterminal.stop
Outgoing lifecycle events:
terminal.openedterminal.outputterminal.exitedterminal.error
Implementation notes:
- The agent opens a PTY-backed interactive shell rather than reusing the non-interactive task executor
- Shell resolution tries
$SHELL,/bin/bash,/bin/zsh, then/bin/sh - Unix PTY startup falls back across multiple modes:
pty+cttypty-no-cttypty-minimal
- The terminal session environment sets
TERM=xterm-256colorandPAGER=cat - Output is chunked and flushed on a timer so the web console receives live updates without waiting for more keystrokes
- On constrained hosts, fallback PTY modes may log reduced job-control capability while remaining usable
terminal.stoprequests a remote shell shutdown, and the API applies a timeout fallback if the shell disappears without a final clean exit event
The agent executes shell.exec tasks in a controlled non-interactive environment:
PAGER=catCOLUMNS=100000- graceful cancellation with log drain timeout
- scheduled tasks use the same execution path as manually queued tasks
- when installed through the bootstrap installer, shell and package tasks run under the
noderaxuser shell.execdoes not auto-elevate to root; it runs in thenoderaxuser context by default- package operations can elevate through passwordless
sudo -n, but only forapt-get install,apt-get remove, andapt-get purge - agent self-update can elevate through passwordless
sudo -n, but only for the dedicated/usr/local/libexec/noderax-agent-self-updatehelper - ad-hoc root shell commands are intentionally out of scope for the bundled sudoers profile
For package listing on Debian/Ubuntu, the agent uses optimized dpkg -l parsing to return structured package metadata.
cmd/agent: application entrypoint and CLI dispatchinternal/agent: enrollment, identity persistence, bootstrapinternal/agentctl: install, service management, config CLIinternal/api: HTTP client and API modelsinternal/tasks: HTTP claim loop and task executioninternal/metrics: metrics workerinternal/realtime: Socket.IO client and handlersinternal/system: host and system information helpersscripts: installation entrypoints
Recommended checks:
go test ./...
go vet ./...Run tests:
go test ./...Build locally:
go build -o noderax-agent ./cmd/agentRun in foreground:
cp config.example.json config.json
./noderax-agent enroll
./noderax-agent-
Linux installation assumes
systemd. -
The managed service config path can be overridden with
NODERAX_CONFIG_FILE. -
API-side realtime task push is not the default control path; HTTP claiming should be considered the normal operating mode.
-
Interactive terminals are the main exception: they depend on the agent realtime socket being healthy.
-
When a node is put into maintenance mode from the control plane, the API stops assigning new work to that node while in-flight tasks are allowed to finish.
