HELP
Deploy apps
Ship your app to a fleet with the nodex CLI: containers to Linux devices, WebAssembly modules to ESP32 boards.
Before you start
- Install the nodex CLI (Windows, macOS & Linux)
curl -fsSL https://raw.githubusercontent.com/adhuldas/nodexa-cli/main/install.sh | sh nodex --version - Find your Fleet ID
Open Fleets, pick a fleet, and copy the Fleet ID from the fleet summary card.
- Create a deployment token
On the same fleet page, click Deployment Token and generate one. It's shown only once, so store it in a password manager or your CI/CD secrets. Never commit it to a repository.
In CI, pass both values as environment variables instead of flags:
export NODEXA_FLEET_ID="<fleet-id>" export NODEXA_API_TOKEN="<api-token>" nodex push
Deploy containers
Devices running nodexOS on Linux (Raspberry Pi, BeagleBone, Variscite and others) run your services as containers built from Docker images. nodex push builds each image, pushes it to the Nodexa registry and creates a new release for the fleet. Docker must be installed on the machine you push from; the devices themselves don't need it.
Option 1: a single Dockerfile
Run from a folder with a Dockerfile. The service name comes from the folder name; override it with --service <name>.
cd my-app # contains a Dockerfile
nodex push --fleet-id <fleet-id> --token <api-token>Option 2: docker-compose.yml
A docker-compose.yml or compose.yml is picked up automatically. Services with a build block are built; services with only an image are pulled, retagged and pushed without rebuilding.
services:
web:
build: .
ports:
- "80:8080"
firmware:
image: ghcr.io/my-org/firmware:latestnodex push --fleet-id <fleet-id> --token <api-token> -c docker-compose.ymlOption 3: a nodexa.yml manifest
For multi-service releases, describe each service in nodexa.yml at the project root. It takes priority over compose files. Point to another file with -f <path>.
platform: linux/arm64 # optional default for every service
services:
- name: web
dockerfile: Dockerfile
context: .
- name: worker
dockerfile: worker/Dockerfile
context: worker/
platform: linux/arm/v7 # optional per-service override
- name: firmware
image: ghcr.io/my-org/firmware:v1.2.0Match your device's CPU
Build for the architecture your devices run, or containers fail to start with exec format error. Set it with --platform, the NODEXA_PLATFORM variable, or platform: in the manifest. Separate several with commas to build a multi-platform image.
| Device | Platform |
|---|---|
| Raspberry Pi 4 (64-bit) | linux/arm64 |
| BeagleBone Black (ARMv7, 32-bit) | linux/arm/v7 |
| x86_64 gateways | linux/amd64 |
nodex push --fleet-id <fleet-id> --token <api-token> --platform linux/arm/v7Pre-built images from private registries
To pull private images (GitHub Container Registry, Docker Hub, ECR…), put credentials in registry.yml next to your project. It's detected automatically, or pass -r <path>.
ghcr.io:
username: my-github-username
password: ghp_personalAccessTokenWithReadPackagesKeep registry credentials out of version control:
echo "registry*.yml" >> .gitignoreAfter the push
The new release appears in the fleet's Releases tab. Each device picks it up on its next update check (set per device under Advanced settings when adding it), pulls the images and restarts the changed services. Follow progress in the device's Logs.
Troubleshooting
Killed: 9when running wasi-sdk on macOSmacOS blocks unsigned tools downloaded with a browser. The
curlinstall above avoids this; if you downloaded wasi-sdk in a browser, clear the flag:xattr -dr com.apple.quarantine ~/wasi-sdk'stdio.h' file not foundwhen building for ESP32Recent wasi-sdk versions dropped the old target name. Use
--target=wasm32-wasip1instead ofwasm32-wasi.- Containers fail with
exec format error The image was built for a different CPU. Push again with the right
--platform.- ESP32 device reports a failed deployment
Check the device's logs. A container image pushed to an ESP32 fleet fails with a message saying so; an app that ran out of memory shows the free heap. Build with the flags above and keep the app small.
nodex pushsays the token is invalidThe token may have been revoked or mistyped. Generate a new one from the fleet's Deployment Token dialog and check that the Fleet ID is correct.
Before you start
- Install the nodex CLI (Windows, macOS & Linux)
curl -fsSL https://raw.githubusercontent.com/adhuldas/nodexa-cli/main/install.sh | sh nodex --version - Find your Fleet ID
Open Fleets, pick a fleet, and copy the Fleet ID from the fleet summary card.
- Create a deployment token
On the same fleet page, click Deployment Token and generate one. It's shown only once, so store it in a password manager or your CI/CD secrets. Never commit it to a repository.
In CI, pass both values as environment variables instead of flags:
export NODEXA_FLEET_ID="<fleet-id>" export NODEXA_API_TOKEN="<api-token>" nodex push
Deploy to ESP32
ESP32 boards can't run containers. Your app is a WebAssembly module built for WASI, which the Nodexa firmware runs directly. nodex push uploads the .wasm file as-is, so Docker isn't needed.
A new board needs nodexOS first; see OS installation.
Supported on ESP32 and ESP32-S3, not on the ESP32-S2. ESP32 devices need a fleet of their own: a fleet with container devices can't also run ESP32 boards.
- Install wasi-sdk (the WebAssembly C compiler)
macOS:
mkdir -p ~/wasi-sdk curl -fsSL https://github.com/WebAssembly/wasi-sdk/releases/download/wasi-sdk-34/wasi-sdk-34.0-$(uname -m)-macos.tar.gz \ | tar -xz -C ~/wasi-sdk --strip-components=1Linux:
mkdir -p ~/wasi-sdk curl -fsSL https://github.com/WebAssembly/wasi-sdk/releases/download/wasi-sdk-34/wasi-sdk-34.0-$(uname -m | sed s/aarch64/arm64/)-linux.tar.gz \ | tar -xz -C ~/wasi-sdk --strip-components=1Windows (PowerShell):
curl.exe -fsSL -o wasi-sdk.tar.gz https://github.com/WebAssembly/wasi-sdk/releases/download/wasi-sdk-34/wasi-sdk-34.0-x86_64-windows.tar.gz $null = mkdir -Force $HOME\wasi-sdk tar -xzf wasi-sdk.tar.gz -C $HOME\wasi-sdk --strip-components=1 - Write your app
Anything written to
stdoutorstderrappears in the device's logs. Pause withnodexa_sleep_ms()rather thansleep()or a busy loop, so the app can be stopped cleanly when a new release arrives.#include <stdio.h> // Provided by the Nodexa ESP32 firmware (see nodexa.h in the SDK). __attribute__((import_module("nodexa"), import_name("sleep_ms"))) void nodexa_sleep_ms(int ms); int main(void) { for (int i = 1;; i++) { printf("hello from Nodexa #%d\n", i); // shows in the device log nodexa_sleep_ms(5000); } } - Build the module
These flags keep the app within one 64 KB page of memory, which matters on a plain ESP32.
macOS and Linux:
~/wasi-sdk/bin/clang --target=wasm32-wasip1 -Os \ -Wl,--strip-all -Wl,-z,stack-size=8192 -Wl,--initial-memory=65536 \ -o hello.wasm main.cWindows (PowerShell):
& $HOME\wasi-sdk\bin\clang.exe --target=wasm32-wasip1 -Os ` "-Wl,--strip-all" "-Wl,-z,stack-size=8192" "-Wl,--initial-memory=65536" ` -o hello.wasm main.c - Point nodexa.yml at the module
services: - name: hello wasm: hello.wasm - Push it to the fleet
nodex push --fleet-id <fleet-id> --token <api-token>Devices download the module on their next heartbeat (every 30 seconds), stop the old version and start the new one. Open a device and check its Logs to see the output.
Device functions
Besides standard WASI (stdio, clocks, environment, arguments), apps can import these from the nodexa module. Declarations are in sdk/include/nodexa.h of the Nodexa ESP32 SDK.
| Function | What it does |
|---|---|
log | Writes a line to the device log at a level (error, warn, info, debug) |
sleep_ms | Sleeps; also where the app stops when it's being replaced or stopped |
uptime_ms, time_ms | Milliseconds since boot, and since the Unix epoch (0 until the clock is set) |
gpio_mode, gpio_write, gpio_read | GPIO access; flash and PSRAM pins are refused (return -1) |
Configuration and limits
- Variables: fleet and device variables reach the app as environment variables (
getenv()). - Restarts: apps that exit are restarted according to their restart policy, backing off from 1 to 60 seconds.
- Memory: a small app needs about 110 KB of heap. A plain ESP32 fits one or two apps; an ESP32-S3 with PSRAM fits more. An app that doesn't fit shows as failed, and the device log shows the free heap.
- Stopping: an app that doesn't reach
nodexa_sleep_ms()within 10 seconds of being stopped makes the device reboot. - Ports, volumes and networks from container setups are ignored.
Troubleshooting
Killed: 9when running wasi-sdk on macOSmacOS blocks unsigned tools downloaded with a browser. The
curlinstall above avoids this; if you downloaded wasi-sdk in a browser, clear the flag:xattr -dr com.apple.quarantine ~/wasi-sdk'stdio.h' file not foundwhen building for ESP32Recent wasi-sdk versions dropped the old target name. Use
--target=wasm32-wasip1instead ofwasm32-wasi.- Containers fail with
exec format error The image was built for a different CPU. Push again with the right
--platform.- ESP32 device reports a failed deployment
Check the device's logs. A container image pushed to an ESP32 fleet fails with a message saying so; an app that ran out of memory shows the free heap. Build with the flags above and keep the app small.
nodex pushsays the token is invalidThe token may have been revoked or mistyped. Generate a new one from the fleet's Deployment Token dialog and check that the Fleet ID is correct.
