Skip to main content

/docs/node-setup

Run a node in under 8 minutes

This guide uses the Rust binary (fastest path) with Ollama as the local inference backend. If you need per-request control or want to build on top of the stack, see the client SDK reference. To point existing OpenAI/Ollama/Anthropic tools at the mesh — or co-host one with iicp-node serve --with-proxy — see the proxy guide.

Use this when you want to provide compute. Install the node, make sure a local model such as Ollama is available, then run iicp-node serve. The node registers, advertises what it can do, and starts heartbeating to the directory.
Install directly from pip, npm, or cargo. For the multi-platform installer, download it, inspect it, then run it.
Switch to the full guide for backend choices, port 9484, service setup, and troubleshooting.
Platform support: Linux x86_64, macOS arm64, macOS x86_64, Windows x86_64. The binary is statically linked — no runtime dependencies. Windows operators may also use WSL2 (Ubuntu 22.04+) and follow the Linux steps if preferred.
IICP is currently in Beta. The iicp-node CLI ships in every published SDK, and interested operators can join the Beta network. Install directly with pip, npm, or cargo. The reviewed installer supports all three SDKs when downloaded and inspected first. Then iicp-node serve.
Optional convenience

Enable shell completion

SDK release 0.7.109 and later can generate completion for Bash, Zsh, Fish, and PowerShell. The generator uses a fixed command catalog. It does not inspect your operator identity, saved nodes, credentials, or the network.

# Bash — current shell
source <(iicp-node completion bash)

# Zsh — current shell
source <(iicp-node completion zsh)

# Fish — current shell
iicp-node completion fish | source

# PowerShell — current shell
iicp-node completion powershell | Out-String | Invoke-Expression

Add the matching command to your shell startup file to enable completion in future sessions. You can inspect the generated script first by running iicp-node completion <shell> without a pipe.

Operator levels

Choose how far you want to go today.

1

Install the binary

Direct registry installs:

pip install iicp-client
npm install -g @iicp/client
cargo install iicp-client --features nat,iicp-tcp

Multi-platform installer — inspect first:

curl -fsSL https://iicp.network/install.sh -o iicp-install.sh
less iicp-install.sh
sh iicp-install.sh

Fast path after you trust it:

curl -fsSL https://iicp.network/install.sh | sh

Windows operators can inspect the script the same way before running it:

irm https://iicp.network/install.ps1 -OutFile iicp-install.ps1
notepad .\iicp-install.ps1
powershell -ExecutionPolicy Bypass -File .\iicp-install.ps1

# Fast path
irm https://iicp.network/install.ps1 | iex
What the installer does:
  • Detects your platform and installs the published IICP client.
  • Adds the iicp-node CLI.
  • Does not require an account, API key, or private key from you.
  • Does not take control of your model; you decide which backend and model to expose.

The installer detects your platform, auto-resolves dependencies (language runtime + Ollama), and installs the published iicp-node CLI; defaults to the Python SDK (pass --rust / --typescript).

Or install directly from a registry — all ship the same iicp-node CLI (public package, no git clone required):

pip install iicp-client                            # PyPI
npm install -g @iicp/client                       # npm
cargo install iicp-client --features nat,iicp-tcp  # crates.io (recommended)

Verify the install:

iicp-node --help
2

Token (auto-assigned — no action needed)

The directory assigns a unique node token when the binary first registers. You do not need to generate one — the token is returned in the registration response and stored in memory automatically.

How it works: on startup the node calls POST /api/v1/register. The directory generates and returns three credentials — all stored automatically by the node runtime:

  • node_token — used for heartbeat, deregister, CIP task auth (Authorization: Bearer)
  • proxy_token — used for POST /v1/telemetry proxy-observed metrics reporting (distinct token, same Authorization: Bearer header)
  • node_hmac_key — used for CIP worker receipt signing (HMAC-SHA256; provisioned automatically, not for Bearer auth)

All three are provisioned on first registration and re-provisioned on re-registration. The node runtime handles them — you only need node_token if building a custom client.

Offline / dev mode: pass --skip-registration (or IICP_SKIP_REGISTRATION=true) to run the node without contacting the directory at all — useful for testing or air-gapped environments.

3

Configure your node

The node is configured through environment variables (each has a matching iicp-node serve flag). Only the backend URL and model are required — everything else has a sensible default.

# Required
export IICP_BACKEND_URL=http://localhost:11434   # Ollama / vLLM / OpenAI-compatible
export IICP_BACKEND_MODEL=llama3.2               # model to advertise + dispatch to

# Recommended for a publicly reachable node
export IICP_PUBLIC_ENDPOINT=https://my-node.example.com:9484  # reachable from outside
export IICP_REGION=eu-central                    # free-form: eu-central | us-east | us-west | ap-southeast | ap-northeast | sa-east

# Optional
export IICP_BACKEND_TYPE=openai_compat           # openai_compat (default) | vllm | llamacpp | meshllm | anthropic
export IICP_BACKEND_API_KEY=...                  # bearer / x-api-key for the backend (empty = none)
export IICP_PORT=9484                            # listen port (default 9484)
export IICP_MAX_CONCURRENT=4                     # concurrent task cap (default 4)
# export IICP_POLICY_MANIFEST_FILE=~/.iicp/node-policy.json  # optional signed public handling policy
# export IICP_SKIP_REGISTRATION=true             # offline / dev mode — don't contact the directory
# export IICP_DIRECTORY_URL=https://iicp.network/api   # override only if self-hosting

public_endpoint must be reachable by other nodes — this usually means opening port 9484 on your router. Port-forwarding guide → The node_idis a UUID generated automatically on first start — you don't need to set it.

Optional signed policy. If you want clients to filter your node by a public handling policy, point IICP_POLICY_MANIFEST_FILE (or --policy-manifest) at a local JSON document. The client signs it with your operator identity and includes it on registration and recovery re-registration. The private operator key and source-file path stay local. This is tamper-evident operator evidence, not a privacy or legal certification.
Backends. IICP_BACKEND_TYPE (or --backend-type) selects the inference engine: openai_compat (default — Ollama, LM Studio, any OpenAI /v1 server), vllm, llamacpp, or meshllm for a local MeshLLM gateway at http://localhost:9337/v1 (stable chat capability), or anthropic for a native Anthropic Messages API (Claude) node. With anthropic the backend URL defaults to https://api.anthropic.com and IICP_BACKEND_API_KEY is sent as thex-api-key header. A Claude-backed node looks identical to any other node to IICP clients — the SDK translates the chat task to/from the Messages API. All three SDKs (Python, TypeScript, Rust) support every backend.
MeshLLM on Apple Silicon. The optional helper scripts/meshllm_local.sh installs a checksum-verified MeshLLM release as a user service, then checks its local /v1 API before creating an IICP node:
scripts/meshllm_local.sh install
scripts/meshllm_local.sh service-install
scripts/meshllm_local.sh smoke
scripts/meshllm_local.sh node-install
This profile uses MeshLLM's --automode, which joins the MeshLLM public mesh. The IICP node is created only after the local smoke check succeeds. The managed service checks for MeshLLM's verified bundled updates when it starts; use an explicit versioned install and smoke check when you need to choose or roll back a release. The helper defaults to a 16 GB MeshLLM planning budget; lower it withIICP_MESHLLM_MAX_VRAM_GBbefore installing the service if your machine needs more headroom. MeshLLM describes the local inference runtime, not the IICP node's location: setIICP_REGIONto the geographic region where the node operates. IICP uses the local OpenAI-compatible gateway only; it does not publish MeshLLM peer or topology details. A directory profile therefore shows the node's capability and geographic operating region, not an “LLM mesh” region or an internal MeshLLM route map.
Modalities. Chat nodes advertise their accepted input modalities incapabilities[].input_modalities: text by default, plus image when a vision model is detected (name contains vl, vision, llava, or omni) and audio for audio models (audio, voxtral, omni). Clients narrow discovery with /api/v1/discover?view=public&intent=…&modality=image (or audio) to find vision/audio-capable nodes. Image and audio are modalities of chat, not separate intents — back-compatible with text-only nodes.
4

Start Ollama (if not running)

# Install Ollama from https://ollama.com if needed
ollama serve &
ollama pull llama3.2

The node will fail startup with a clear error if the backend is unreachable. Any OpenAI-compatible backend works — just point IICP_BACKEND_URL at vLLM, llama.cpp, or LM Studio instead of Ollama. To run a Claude-backed node instead, set IICP_BACKEND_TYPE=anthropic and IICP_BACKEND_API_KEY (no local model needed).

5

Start the node

iicp-node serve

On startup the node:

  1. Registers with the directory (POST /api/v1/register)
  2. Verifies the backend is reachable
  3. Starts a heartbeat loop (every 30s)
  4. Listens for inbound task requests on port 9484

Verify registration:

curl -s 'https://iicp.network/api/v1/discover?view=public&intent=urn:iicp:intent:llm:chat:v1' \
  | python3 -m json.tool

Your node should appear in the nodes array within 30 seconds. Its health_label may start below healthy until routing and latency evidence exists; heartbeat, public reachability, encryption readiness and task history are separate signals. Or browse iicp.network/nodes to see heartbeating nodes visually — find yours by region or node ID prefix.

Reachability tier. Each node in a discover response carries a reachability_tier field: direct(liveness-verified — either the directory's TCP probe reached you, or your node answered the HMAC liveness challenge in a heartbeat within the last 5 minutes; v0.7.48+ always answers the challenge, so the TCP probe becomes a fallback only) or relay (routed via a relay peer — designed path for CGNAT or IPv6-only nodes). Default discovery returns both tiers; a heartbeating node is never hidden just for lacking direct dial-back. Clients prefer direct and fall back to relay. Relay node (v0.7.45+): to serve as a relay for CGNAT/IPv4 operators, add --relay-capable (or IICP_RELAY_CAPABLE=1) and expose --relay-accept-port (default 9485) publicly — a Cloudflare Tunnelworks without port-forwarding. Current v0.7.109 SDKs keep verified direct reachability first. If direct IPv4, IPv6 or pinhole reachability is unavailable or unverified, they can use a Cloudflare Quick Tunnel for the node's own public endpoint before falling back to a configured or auto-elected relay path. Treat relay/tunnel paths as experimental resilience tools, not as a direct-routing replacement. When a temporary route fails, current clients fail closed and let the process supervisor retry instead of advertising an unsafe endpoint.

Monitor your node

The node serves three local endpoints on its listen port (default 9484) — no separate dashboard process. Health and live load:

curl http://localhost:9484/iicp/health   # status + current load
curl http://localhost:9484/metrics       # Prometheus metrics (tasks, latency, errors)

The /metrics endpoint exposes counters for tasks completed, request latency, and errors in Prometheus format — point a Prometheus/Grafana stack at it for dashboards. (Python/TypeScript: install the metrics optional dependency; Rust: build with --features metrics.) Structured node events are also written to ~/.iicp/logs/events.jsonl.

To check your credit balance, use the CLI: iicp-node credits (auto-selects your node, or pass a node name). Or query the API directly: GET /api/v1/credits/balance (Bearer node_token). Fleet operators: GET /api/v1/credits/summary returns an operator_wallet block with the combined earned/spent/balance across all your nodes; future mesh usage can spend from that pooled wallet while each debit remains auditable per node (see Credits API). Or browse iicp.network/nodes to see your node live in the mesh. To start earning credits, enable CIP Provider mode in the section below — it lets other agents delegate inference sub-tasks to your node, settled automatically by the coordinator after each sub-task.

Your operator identity

The first time you run a node, the CLI creates an operator identity at ~/.iicp/operator.json. It is an Ed25519 keypair: your operator ID is the public key (the directory stores and cryptographically verifies it), and the private key — the operator secret — stays on your machine and is never sent to the directory. Credits earned by every node you run accumulate to this one identity.

Set a public display name

Your display name is the public, changeable handle shown next to your node on the mesh node list and on the founders leaderboard. It is keyed to your operator ID, so you can change it any time — the change is authenticated by your own operator key (no node token), so only you can rename your identity:

iicp-node operator rename "Ada's Mesh Node"

One signed call updates the single operator record — it is reflected on every node you run and on the founders leaderboard. Your operator ID and any earned founder ranking stay bound to the key; only the display name changes. Your contact e-mail (if set) stays private and is never shown publicly.

Password-protect your key at rest (optional)

By default the operator secret is stored in a permission-restricted (0600) file. For defence in depth you can encrypt it with a passphrase — sealed with AES-256-GCM, key derived via PBKDF2-HMAC-SHA256:

iicp-node operator encrypt          # prompts for a passphrase (one-time)
iicp-node operator decrypt          # restore the plaintext secret

A serving node stays fully headless: set IICP_OPERATOR_PASSPHRASE in the environment and iicp-node serve unlocks the key automatically — there is never an interactive prompt during serve. The same command works in all three SDKs (Python, TypeScript, Rust); an encrypted operator.json created by one opens in the others with the same passphrase.

Troubleshooting

Registration fails with 401

The node's in-memory token no longer matches the directory's record — this usually happens after a partial registration or a crash before the response was stored. Restart the node: it will call POST /register again and receive a fresh token automatically. No manual token generation is needed.

Node disappears from discover after 90s

The heartbeat is not reaching the directory, or the node is deliberately backing off while it rebuilds a public route. Current clients under launchd/systemd/Docker should retry automatically after temporary tunnel/network failures. Check /stats for a recovery window, then verify outbound HTTPS (port 443), local backend health, and that public_endpoint is reachable from outside your network. The heartbeat uses the token assigned during registration — no manual token configuration is required.

Registration fails with 422 (non-routable endpoint)

The directory rejected IICP-E035 — your IICP_PUBLIC_ENDPOINT resolves to a private or reserved address (localhost, 192.168.x.x, .local, Docker service name, etc.). Set a publicly-routable DNS name or IP. If you're behind CGNAT or have no static IP, use a Cloudflare Tunnel first — see the port-forwarding guide.

Backend unreachable at startup

Verify Ollama is running: curl http://localhost:11434/api/tags. If using vLLM, check that the server is bound to the expected port.

Optional: Enable Cooperative Inference (CIP Provider)

The Cooperative Inference Protocol (CIP) lets your node serve inference sub-tasks delegated by other IICP agents — earning credits per completed request. CIP is opt-inand off by default.

Set one environment variable, then start your node — same for the Python, TypeScript, and Rust iicp-node CLI:

export IICP_CIP_ALLOW_WORKER=true   # opt in to CIP Provider mode
export IICP_MAX_CONCURRENT=4         # cap simultaneous tasks (default 4; excess gets IICP-E021)

iicp-node serve

Inference only: a CIP worker serves model-inference sub-tasks and nothing else — it never executes tools or touches your filesystem on a coordinator's behalf. There is no remote code-execution surface to disable.

Reputation: new nodes start at 0.50. The current deployed score combines reported task outcomes with latency and may fall for a slow successful task. It is a routing-history signal, not a fraud verdict, uptime measure, or answer-quality certificate.

Capacity: IICP_MAX_CONCURRENT caps simultaneous tasks (CIP and direct alike, default 4). Excess requests receive IICP-E021 immediately — no silent queuing.

Credit settlement: after each completed sub-task, the coordinator automatically verifies your signed receipt and submits the credit award to the directory. Credits appear in your directory balance — check with GET /api/v1/credits/balance (Bearer node_token). The local dashboard Credits Reported counter only tracks direct non-CIP awards.

Status: CIP Provider mode is Phase 5B. The conformance level (CIP-Provider) is declared automatically on registration. See the spec §S.12 for full details, or the CIP quickstart to see how coordinators dispatch tasks to your node.

Keep your node running

The steps above start the node in the foreground — closing the terminal stops it and removes it from the directory after the 90-second heartbeat timeout. Use a system service to keep your node online persistently.

Current self-recovery behaviour. With a current client, a supervised node retries temporary failures instead of staying half-advertised: direct routes are preferred, automatic Quick Tunnel creation is paced across local IICP services, Cloudflare rate-limit cooldowns are respected, and temporary route failures exit with a retry-friendly status for launchd/systemd/Docker. After laptop sleep or Wi-Fi changes, the node may disappear for a few minutes while route evidence rebuilds; check /stats before restarting everything manually. Relay-capable nodes intentionally do not chain through another relay during tunnel cooldown.
Three different recovery layers. The operating-system service manager starts the process and restarts it after an exit. The IICP supervisor repairs recoverable tunnel, directory, and provider failures without restarting the whole process. Runtime health determines whether the local executor is still making progress. A node can therefore be live but temporarily not ready while its directory or tunnel recovers. Host freezes, power loss, kernel failures, and storage failures remain host-level concerns. A restart policy alone does not detect a process that is still present but stalled.

Linux — systemd

Current source builds provide a user-service installer. Check that your installed client lists it before use; published clients without this command should retain their existing reviewed unit until the next SDK release.

iicp-node service --help
iicp-node service install --node mynode --platform systemd

# Install and enable without starting immediately:
iicp-node service install --node mynode --platform systemd --no-start

# Inspect effective state and logs:
iicp-node service status --node mynode --platform systemd
journalctl --user -u network.iicp.node.mynode.service -f
loginctl show-user "$USER" --property=Linger

This is a user service and never silently escalates privileges or enables lingering. If Linger=no, it may not start at boot before login; decide separately whether enabling user lingering is appropriate for this account. Installation reloads systemd, enables and starts the service by default, then reports its effective state. Native runtime-watchdog notification is optional and not enabled by the ordinary unit.

macOS — launchd

Use the same user-service command when it is present in your installed client:

iicp-node service install --node mynode --platform launchd
iicp-node service status --node mynode --platform launchd
iicp-node service restart --node mynode --platform launchd
tail -f ~/.iicp/logs/network.iicp.node.mynode.out.log   ~/.iicp/logs/network.iicp.node.mynode.err.log

The generated LaunchAgent uses RunAtLoad and KeepAlive. launchd supervises the process; it does not define IICP runtime liveness.

Local health diagnosis. Builds containing the runtime-health work write a private snapshot and expose iicp-node healthcheck --node mynode --json. This separates local liveness, readiness, subsystem state, and external connectivity. It does not change the provider-capacity meaning of /iicp/health, and a /metrics503 response is not proof that the runtime is dead. Non-systemd Linux and container monitors can consume the local healthcheck without adopting systemd semantics.

Quick option — nohup

For a fast background run without a service file:

nohup iicp-node serve > /tmp/iicp-node.log 2>&1 &
tail -f /tmp/iicp-node.log

The process survives terminal close but not reboots. Use a systemd or launchd service for a persistent node.

Verify your node is routing tasks:

iicp-node query "What is the capital of France?"
# → discovers mesh nodes, submits to best available node, prints reply

# Check your node's activity log (written by iicp-node serve automatically):
cat ~/.iicp/logs/events.jsonl     # structured NDJSON: register, heartbeat, task events

Node not showing up? Browse the node directory to check, then see troubleshooting · Email [email protected] · See the client SDK reference for advanced configuration · point existing tools at the mesh with the proxy · Have an MCP server? MCP gateway.