AI Worker built with OpenClaw and NEAR AI Cloud API.
| Directory | Purpose |
|---|---|
| worker/ | OpenClaw worker Docker image (Dockerfile, entrypoint, config template). Single-tenant runs use this. |
| compose-api/ | Multi-tenant Compose API (Rust/Axum). Spawns one Docker Compose project per user; requires Docker socket. |
| ssh-bastion/ | SSH bastion service. Proxies SSH connections to worker instances via a single port (2222). |
| deploy/ | Deployment configs and scripts: compose files (single-tenant, multi-tenant, nginx/HTTPS), nginx template, env examples, deploy.sh, build-image.sh. |
- NEAR AI Cloud Integration: Uses NEAR AI Cloud as the model provider
- Docker Ready: Easy deployment with Docker and Docker Compose
- Docker and Docker Compose
- NEAR AI Cloud API key
Create a .env file (copy from worker/env.example):
cp worker/env.example .env
# Edit .env with your credentialsRequired variables:
NEARAI_API_KEY: NEAR AI Cloud API key
Optional variables:
OPENCLAW_FORCE_CONFIG_REGEN: Set to1to force regeneration of config from template (default:0)OPENCLAW_GATEWAY_BIND: Gateway bind address —lan(default) orloopback. See Gateway binding and security.SSH_PUBKEY: Your SSH public key (e.g. contents of~/.ssh/id_ed25519.pub). When set, enables SSH server on port 2222 for key-based login as useragent. See SSH access.
From the repo root:
# Start the service (builds worker image if needed)
docker compose -f deploy/docker-compose.yml up -d
# Or start in foreground to see logs:
docker compose -f deploy/docker-compose.yml updocker compose -f deploy/docker-compose.yml logs -f openclaw-gatewayFor deploying multiple isolated OpenClaw instances (one per user), use the multi-tenant setup with the Compose API.
- Docker and Docker Compose
- NEAR AI Cloud API key
- A server with ports 80, 443, and 2222 (SSH bastion) accessible
-
Configure environment:
cp deploy/env.prod.example deploy/.env.prod # Edit deploy/.env.prod: # - OPENCLAW_HOST_ADDRESS (your server's public IP/hostname) # - ADMIN_TOKEN will be auto-generated if not set # Note: NEARAI_API_KEY is provided per-user in the create request
-
Deploy (from repo root):
chmod +x deploy/dev.sh ./deploy/dev.sh
-
Create users via Compose API:
# Set your admin token (from deploy/.env.prod) export ADMIN_TOKEN="your-token-here" # Create a user (with their NEAR AI API key and optional SSH public key) curl -X POST http://<server>:47392/users \ -H "Content-Type: application/json" \ -H "Authorization: Bearer $ADMIN_TOKEN" \ -d '{ "user_id": "alice", "nearai_api_key": "sk-user-nearai-api-key", "ssh_pubkey": "ssh-ed25519 AAAA... user@host" }' # Response includes gateway port, SSH port, and connection info: # { # "user_id": "alice", # "token": "abc123...", # "gateway_port": 19001, # "ssh_port": 19002, # "url": "http://<server>:19001", # "dashboard_url": "http://<server>:19001/?token=abc123...", # "ssh_command": "ssh -p 19002 agent@<server>", # "status": "running" # }
All API endpoints (except /health) require authentication via Bearer token:
curl -H "Authorization: Bearer $ADMIN_TOKEN" http://<server>:47392/usersThe ADMIN_TOKEN must be a 32-character hex string. Generate one with:
openssl rand -hex 16| Method | Endpoint | Description |
|---|---|---|
GET |
/health |
Health check (no auth required) |
POST |
/users |
Create user ({"user_id": "...", "nearai_api_key": "...", "ssh_pubkey": "..."}) |
GET |
/users |
List all users |
GET |
/users/{id} |
Get user details |
DELETE |
/users/{id} |
Delete user and container |
POST |
/users/{id}/restart |
Restart user's container |
POST |
/users/{id}/stop |
Stop user's container |
POST |
/users/{id}/start |
Start user's container |
Each instance gets:
- Web UI: Accessible via subdomain
https://<instance-name>.<domain>(proxied through nginx) - SSH: Accessible via the SSH bastion on port 2222, using the instance name as username:
# Interactive shell ssh -p 2222 <instance-name>@<server> # Run a command ssh -p 2222 <instance-name>@<server> ls -la # SCP file transfer (use -O for legacy SCP protocol) scp -O -P 2222 file.txt <instance-name>@<server>:~/
The SSH public key provided during instance creation is used for authentication. The bastion looks up the key from compose-api and proxies the connection to the correct worker container.
Note: SFTP is not supported through the bastion. Use SCP with -O (legacy protocol) instead.
Production HTTPS uses nginx on the host with certbot for Let’s Encrypt. No reverse proxy runs in Docker.
-
Set domain in env
- In
.env.prod:OPENCLAW_DOMAIN=openclaw.example.com(your domain).
- In
-
Start the stack (management API only; nginx runs on the host)
docker compose -f docker-compose.nginx.yml --env-file .env.prod up -d
The API listens on
127.0.0.1:47392so only nginx can reach it. -
Configure nginx
- Copy
nginx-openclaw.confinto your nginx config (e.g./etc/nginx/sites-available/openclaw). - Replace
OPENCLAW_DOMAINin the file with your domain (e.g.openclaw.example.com). - Enable the site and reload nginx:
sudo nginx -t && sudo systemctl reload nginx.
- Copy
-
Get certificates
sudo certbot --nginx -d openclaw.example.com -d "*.openclaw.example.com"Certbot will add
listen 443 ssland certificate paths to the server block. -
DNS
- A record:
openclaw.example.com→ your server IP. - A record:
*.openclaw.example.com→ your server IP.
- A record:
After this, the main domain serves the Compose API over HTTPS, and each user gets a subdomain (e.g. alice.openclaw.example.com) proxied to their OpenClaw instance automatically.
- The first device connecting to each user's instance is auto-approved
- Subsequent devices require manual approval via Telegram bot or CLI:
# Via container CLI (gateway container name is openclaw-<user_id>-gateway-1) docker exec -u agent openclaw-<user_id>-gateway-1 openclaw devices list docker exec -u agent openclaw-<user_id>-gateway-1 openclaw devices approve <request-id>
Ensure these ports are open:
80- HTTP (nginx, redirects to HTTPS / certbot challenges)443- HTTPS (nginx, proxies to compose-api and worker instances)2222- SSH bastion (proxies SSH to worker instances)
# Check configuration (single-tenant: use deploy/docker-compose.yml)
docker compose -f deploy/docker-compose.yml exec openclaw-gateway openclaw doctor
# List available models
docker compose -f deploy/docker-compose.yml exec openclaw-gateway openclaw models listThe configuration is automatically generated from environment variables on first run. The entrypoint script creates /home/agent/.openclaw/openclaw.json with:
- NEAR AI Cloud as the model provider
- auto (
nearai/auto) as the default primary model, letting NEAR AI Cloud route to the best available model
The worker is preconfigured to use NEAR AI Cloud's auto routing, which automatically selects the best available model for each request.
| Model | ID | Description |
|---|---|---|
| auto (default) | nearai/auto |
NEAR AI Cloud model routing — automatically selects the best available model. |
Using a specific model
- Primary model: The default is
nearai/auto. To use a specific NEAR AI model, editopenclaw.json(or the template) and setagents.defaults.model.primaryto a specific model ID, then add the model tomodels.providers.nearai.models. - Per-request: When calling the gateway API (chat completions or responses), specify the
modelparameter in your request body with the desired model ID. - List at runtime: Run
openclaw models listinside the container to see all configured models and their IDs.
Important: The configuration file is only generated once. If you change environment variables after the first run, the configuration will not be automatically updated.
To update the configuration after changing environment variables, you have three options:
-
Force regeneration (recommended): Set
OPENCLAW_FORCE_CONFIG_REGEN=1and restart the container:# In deploy/docker-compose.yml, add to environment: OPENCLAW_FORCE_CONFIG_REGEN: "1" # Or when running: docker compose -f deploy/docker-compose.yml run -e OPENCLAW_FORCE_CONFIG_REGEN=1 openclaw-gateway
-
Delete and regenerate: Remove the config file and restart:
docker compose -f deploy/docker-compose.yml exec openclaw-gateway rm /home/agent/.openclaw/openclaw.json docker compose -f deploy/docker-compose.yml restart openclaw-gateway -
Manual edit: Edit the config file directly:
docker compose -f deploy/docker-compose.yml exec openclaw-gateway vi /home/agent/.openclaw/openclaw.json
After the first run, you can edit /home/agent/.openclaw/openclaw.json directly to:
- Change the primary model (
agents.defaults.model.primary) to any of the available model IDs (see Available Models) - Add or remove models in
agents.defaults.models - Adjust concurrency, workspace paths, or gateway settings
This Docker image can be deployed on TEE (Trusted Execution Environment) infrastructure for enhanced security. The container runs with the same configuration and can be deployed using your preferred container orchestration platform on TEE-enabled infrastructure.
Key considerations for TEE deployment:
- Ensure all required environment variables are securely provided
- Use secure secret management systems for API keys and tokens
- Configure appropriate network policies and access controls
- Monitor container health using the built-in healthcheck
- 18789: Gateway WebSocket and HTTP API
- 18790: Browser bridge (if enabled)
- 2222: SSH (when
SSH_PUBKEYis set)
- 80: HTTP (nginx — HTTPS redirect, certbot challenges)
- 443: HTTPS (nginx — proxies to compose-api and worker subdomains)
- 2222: SSH bastion (proxies to worker instances by instance name)
- 8080: Compose API (internal, localhost only behind nginx)
The gateway bind setting controls which network interfaces the gateway listens on:
lan(default): Listens on all interfaces (0.0.0.0). The gateway is reachable from any device on the local network (and from the internet if the host is exposed).loopback: Listens only on localhost (127.0.0.1). Access is limited to the same host. Use this when only local processes or port-forwarding need the gateway.
- su: The
sucommand is available (loginpackage installed), but therootaccount is password-locked by default, sosu -to root will typically not work unless you explicitly set a root password or adjust PAM policy. - sudo: The
agentuser has passwordlesssudoenabled unconditionally (via/etc/sudoers.d/agent). Usesudo su -to become root, orsudo <command>for one-off elevation.
docker compose -f deploy/docker-compose.yml psdocker compose -f deploy/docker-compose.yml logs -f openclaw-gatewaydocker compose -f deploy/docker-compose.yml exec openclaw-gateway openclaw doctordocker compose -f deploy/docker-compose.yml exec openclaw-gateway openclaw models list- Never log sensitive values: The entrypoint script is designed to never log API keys, tokens, SSH keys, or secrets
- Secure log storage: Ensure Docker logs are stored securely and access is restricted
- Environment variables: Use
.envfiles with proper permissions (chmod 600) or secret management systems - Container inspection: Be cautious when using
docker inspectordocker execas these may expose environment variables - Gateway binding: The default is
lan; follow the guidance in Gateway binding and security. SetOPENCLAW_GATEWAY_BIND=loopbackto restrict to localhost only. - SSH: Only enable SSH when needed by setting
SSH_PUBKEY. Use key-based auth only; ensure port 2222 is not exposed to the internet unless you intend external access and have secured the host.
All from repo root. Single-tenant (one worker):
docker build -t openclaw-nearai-worker:latest ./worker- Build the worker imagedocker compose -f deploy/docker-compose.yml up -d- Start the servicedocker compose -f deploy/docker-compose.yml down- Stop the servicedocker compose -f deploy/docker-compose.yml logs -f openclaw-gateway- View logsdocker compose -f deploy/docker-compose.yml exec openclaw-gateway openclaw doctor- Test configurationdocker compose -f deploy/docker-compose.yml exec openclaw-gateway openclaw models list- List available modelsdocker compose -f deploy/docker-compose.yml exec openclaw-gateway /bin/bash- Open shell in containerdocker compose -f deploy/docker-compose.yml down -v- Remove containers and volumes
Multi-tenant (Compose API + per-user workers):
./deploy/dev.sh- Build all images and start the local development stack./deploy/dev.sh --no-build- Start without rebuilding images./deploy/dev.sh --down- Tear down the stack
ssh -o ProxyCommand="openssl s_client -quiet -connect %h:443 -servername %h" root@<instance-id>-22.infra.near.ai- SSH login to CVM instancedocker exec openclaw-gateway openclaw models list- List available modelsdocker exec openclaw-gateway openclaw logs- View logsdocker exec openclaw-gateway openclaw config- Show configdocker exec openclaw-gateway openclaw sysinfo- Show system infodocker exec -it openclaw-gateway /bin/bash- Open shell in container
MIT License - see LICENSE file for details.