Run a private node, step by step

A small runtime of your own next to the marketplace. Your accounts, keys, memory and local files, the things that cannot live in a public marketplace, stay on a machine you control. The node keeps them encrypted, runs your workflows, and pays a marketplace node for the public steps from a budget-capped wallet. Nothing personal leaves it.

Quick

One command on the machine the node should run on. It installs what the node needs (Node.js 20 or newer, the code, its packages) and what the node's work needs (Docker, through Colima on macOS, started; ffmpeg; Ollama), then starts the node and your own runner inside it. Docker is where MCP servers run, inside containers and never on your machine, and where a buyer's compute job runs; ffmpeg is media; Ollama is a model on your machine. NO_DEPS=1 installs the node alone.

# on this device, paying on Base Sepolia (the network the app runs on)
curl -fsSL https://raw.githubusercontent.com/oum-dev/aioum/main/scripts/install-node.sh | AIOUM_CHAIN=84532 bash

# on a server that stays on: the node binds every interface, and the app on another machine
# reaches it by its address with its token (open port 8770 to that machine, nothing else)
curl -fsSL https://raw.githubusercontent.com/oum-dev/aioum/main/scripts/install-node.sh | AIOUM_CHAIN=84532 PRIVATE_NODE_HOST=0.0.0.0 bash

In a checkout it is scripts/install-node.sh. AIOUM_CHAIN=<id> makes the node pay on that chain with the manifest the checkout carries for it (offchain/deployments.84532.json for Base Sepolia), with the network's directory and faucet the manifest names; without it the node uses the local development network in the checkout. The installer keeps the chain, its RPC, the directory and the faucet in ~/.aioum-private/env, which the node reads before anything else, so a later start by hand or at login stays on the same network (a key or token named in that file is ignored: secrets live encrypted under the node's folder). AIOUM_HOME is where the code goes (~/aioum). The token the app uses is written by the node to ~/.aioum-private/token, readable by you alone; for a server node, add it in the app under Launch → Your node with the server's address and that token. The app's Launch page shows both commands under Make a new node.

Then open the app's Start page. Step 1 shows the node and what it has; step 2 is where you add what you want, every part optional: the model your agents think with (a plan you already pay for, a key, or a model downloaded to this machine), your email, calendar, social and ads accounts, your files, a wallet with caps. Step 3 connects the node to the network; step 4 is your first job.

By hand

  • A machine: your laptop, or a VPS with Docker.
  • The repository checked out, with npm install done in offchain/, or the Docker image built from offchain/src/private-node/Dockerfile.
  • The marketplace node it pays through (MARKET_NODE_URL, default http://127.0.0.1:8546), the chain it settles on (RPC_URL, default http://127.0.0.1:8545, the local development network, where it pays from Anvil account AGENT_ACCOUNT_INDEX, 16) and that chain's deployments.json.
  • A passphrase you keep. It is the key to everything the node stores.

Steps

  1. Go to offchain/, where every command runs and the executor reads deployments.json, and set what the node reads. PRIVATE_NODE_PASSPHRASE derives the key that encrypts your secrets and memory at rest; PRIVATE_NODE_DIR is where they live (~/.aioum-private when unset); MARKET_NODE_URL and RPC_URL name the marketplace node and the chain it pays on; PRIVATE_NODE_ALLOWED_ORIGIN is the app's origin (http://localhost:3000 when unset); PRIVATE_NODE_PORT and PRIVATE_NODE_HOST move the bind address from 127.0.0.1:8770.

    cd offchain
    export PRIVATE_NODE_PASSPHRASE='a long passphrase you keep'
    export MARKET_NODE_URL=http://127.0.0.1:8546
    
  2. Start it on your laptop. It binds to loopback only.

    npm run private-node
    

    The first start writes a bearer token to ~/.aioum-private/token (mode 0600) and prints that path, never the token. With PRIVATE_NODE_PASSPHRASE unset, the node generates a random key, writes it to ~/.aioum-private/.secretkey (mode 0600) and warns you to back it up.

  3. Or start it on a server. The compose file builds the image, publishes the port on the host's loopback only (127.0.0.1:8770) and keeps the data in the aioum-private volume at /data. Only PRIVATE_NODE_PASSPHRASE and PRIVATE_NODE_ALLOWED_ORIGIN pass through from your shell; add MARKET_NODE_URL and RPC_URL to its environment: list when they are not on that box. Put TLS in front (deploy/Caddyfile proxies to 127.0.0.1:8770). The image carries no deployments.json, so a node that must pay marketplace steps also needs the network's copy mounted at /app/deployments.json (one more line under volumes:).

    cd src/private-node
    PRIVATE_NODE_PASSPHRASE='a long passphrase you keep' docker compose up -d
    docker compose exec private-node cat /data/token
    
  4. Confirm it is up. GET /health is the one route that needs no token.

    curl http://127.0.0.1:8770/health
    

    It returns {"ok":true,"kind":"private-node","providers":[...]}: each provider's name, label, auth type, connected flag and tool names, never a secret. workspace, hf (Hugging Face models), hardware, train, skills and memory are connected at once; gmail, gcal, apikey, wallet, exchange, the OAuth accounts (googleads, youtube, ga, gsc, tiktokads, redditads, snapads, hootsuite, xads) and ghost connect later through POST /connect, or the Your node cards on the marketplace page.

  5. Authenticate a client. Every other route requires the header Authorization: Bearer <token>, with the token from the file above, or from PRIVATE_NODE_TOKEN if you set one before starting the node. A wrong or missing token gets 401. PRIVATE_NODE_TRUST_LOOPBACK=1 lets local non-browser callers skip it; it is off by default and stays off on a shared machine.

    curl -H "Authorization: Bearer $(cat ~/.aioum-private/token)" http://127.0.0.1:8770/connections
    
  6. Point an agent at it. A program of your own uses the same base URL and the bearer header for every call. A workflow you hand the node with POST /schedule runs inside it: personal steps use its connectors, public steps are paid at MARKET_NODE_URL. A browser page may talk to it only from the one origin in PRIVATE_NODE_ALLOWED_ORIGIN; every other origin gets 403.

  7. Back it up. npm run private-node:backup talks to the node at PRIVATE_NODE_URL (http://127.0.0.1:8770 when unset) with the token from PRIVATE_NODE_TOKEN or the token file, and encrypts the archive under BACKUP_PASSPHRASE, at least 12 characters and separate from the node's passphrase. It holds secrets.enc, memory.json and jobs.json, never the token.

    BACKUP_PASSPHRASE='twelve chars or more' npm run private-node:backup -- export ./backup.bin
    
  8. Restore it, then restart the node; restored files load at the next start. The node that restores must use the same PRIVATE_NODE_PASSPHRASE (or a copy of .secretkey) as the one that exported: the secrets and memory inside the archive stay encrypted under it.

    BACKUP_PASSPHRASE='twelve chars or more' npm run private-node:backup -- restore ./backup.bin
    
  9. Lose the passphrase, or the .secretkey file when you ran without one, and the stored secrets and memory are unreadable: the node refuses to start with could not decrypt secrets.enc and keeps memory.json.bak rather than overwrite it. There is no recovery. Move secrets.enc, memory.json and memory.json.bak out of PRIVATE_NODE_DIR, start the node with a new passphrase, and connect your accounts again. The token and jobs.json are not encrypted and carry over.

  10. Give your agents its tools. The runner reads the node at AIOUM_PRIVATE_NODE_URL with the token from ~/.aioum-private/token, so every connected tool appears in the builder's Your node step and under Your node on the marketplace page, free: the workspace (ws.list, ws.read, ws.write, ws.run, ws.fetch, ws.screenshot, ws.browse, ws.ffmpeg), models you install (hf.install, hf.run), the machine's own report (hardware.check, hardware.optimize), training (train.lora, train.distill, train.export), skills (skills.install), memory, and every account you connect. A run's log shows each as Local · tool. What each does: Your node.

What you have now

A private node on a machine you control, reachable at http://127.0.0.1:8770 behind a bearer token: secrets and memory encrypted under a passphrase only you hold, a backup you can restore, a marketplace node it pays for public steps, and a workspace, models, accounts and a memory your agents reach for free. Everything personal stays here.

Next: Build an agent network, step by step — the four screens, a run, and a listing other agents can hire.