This guide covers using Janee with containerized OpenClaw agents via HTTP transport.
When OpenClaw runs inside a container, the default stdio-based setup doesn't work:
┌──────────────────────────────────────┐
│ Docker Container (agent) │
│ - No access to host filesystem │
│ - No Janee binary │
│ - No ~/.janee/config.yaml │
│ │
│ ✗ Can't spawn `janee serve` │
│ ✗ Can't read encrypted credentials │
└──────────────────────────────────────┘
Mounting secrets into the container defeats Janee's security model — the agent would have direct access to the master key and API credentials.
Janee supports HTTP network transport, enabling this architecture:
┌─────────────────────────┐ ┌──────────────────────────┐
│ Host │ │ Docker Container │
│ │ │ │
│ janee serve │◄─────────┤ Agent (OpenClaw) │
│ --transport http │ HTTP │ janee-openclaw plugin │
│ --port 9100 │ │ config: { │
│ │ │ url: "http://host:9100"│
│ Has: │ │ } │
│ - Master key │ │ │
│ - Encrypted creds │ │ Has: │
│ - ~/.janee/config.yaml │ │ - Nothing! │
└─────────────────────────┘ └──────────────────────────┘
The container connects over the network, agent never sees credentials.
npm install -g @true-and-useful/janee
janee init
janee add stripe --auth-type bearer --key sk_live_...Default (localhost only, recommended):
janee serve --transport http --port 9100
# Listening on http://localhost:9100/mcpCustom host:
# Bind to specific interface
janee serve --transport http --port 9100 --host 172.17.0.1
# Bind to all interfaces (see security warning below)
janee serve --transport http --port 9100 --host 0.0.0.0The MCP endpoint is at /mcp (e.g., http://localhost:9100/mcp).
The container needs to reach the host's localhost. This varies by platform:
macOS / Windows (Docker Desktop):
Use host.docker.internal:
docker run -it \
-e JANEE_URL=http://host.docker.internal:9100/mcp \
my-openclaw-agentLinux:
Use --add-host to map host.docker.internal to the gateway:
docker run -it \
--add-host=host.docker.internal:host-gateway \
-e JANEE_URL=http://host.docker.internal:9100/mcp \
my-openclaw-agentOr use the bridge gateway IP directly (usually 172.17.0.1):
# Find your bridge gateway IP
docker network inspect bridge | grep Gateway
# Start Janee bound to that IP or 0.0.0.0
janee serve --transport http --port 9100 --host 172.17.0.1
docker run -it \
-e JANEE_URL=http://172.17.0.1:9100/mcp \
my-openclaw-agentInstall the plugin in your container's OpenClaw setup:
openclaw plugins install @true-and-useful/janee-openclawConfigure the plugin with the url field in your OpenClaw agent config:
{
agents: {
list: [{
id: "main",
tools: { allow: ["janee"] },
extensions: [{
id: "janee-openclaw",
enabled: true,
config: {
url: "http://host.docker.internal:9100/mcp"
}
}]
}]
}
}Important: When url is set, the plugin connects over HTTP instead of spawning janee serve as a subprocess.
version: '3'
services:
openclaw-agent:
image: my-openclaw-agent:latest
extra_hosts:
- "host.docker.internal:host-gateway"
environment:
- JANEE_URL=http://host.docker.internal:9100/mcp
# No volume mounts needed!
# No secrets in container!On the host:
janee serve --transport http --port 9100
docker-compose upTest the connection from inside the container:
# Enter running container
docker exec -it <container-id> sh
# Test basic connectivity (ping the port)
nc -zv host.docker.internal 9100
# Or on Linux with bridge IP
nc -zv 172.17.0.1 9100If the port is reachable, you should see "succeeded!" or "open". Then try using the OpenClaw agent:
Agent: "List available services"
→ janee-openclaw calls janee_list_services over HTTP
→ Janee responds with ["stripe"]
Agent: "Get recent Stripe customers"
→ janee-openclaw calls janee_execute(capability: "stripe", path: "/v1/customers")
→ Janee proxies to Stripe API with decrypted key
→ Response returned to agent
Default binding: localhost (127.0.0.1)
When Janee binds to localhost, only processes on the same machine can connect. Containers reach localhost via Docker's host.docker.internal or bridge gateway IP.
Trust boundary: Anyone who can connect is trusted. Same as stdio — there's no authentication yet.
Suitable for:
- Trusted local connections (container → host on same machine)
- Development and personal deployments
Not suitable for:
- Public networks
- Multi-tenant systems
- Untrusted containers
0.0.0.0
When you bind to 0.0.0.0, Janee is exposed to:
- All containers on the Docker bridge network
- Other machines on your network (if firewall allows)
Any container that can reach the port can access all configured API credentials.
Only bind to 0.0.0.0 when:
- All containers on the network are trusted, OR
- Docker network ACLs restrict access to specific containers, OR
- Host firewall rules limit connections to specific IPs
Recommended configuration (most restrictive):
# macOS/Windows: localhost only, use host.docker.internal from containers
janee serve --transport http --port 9100 --host localhost
# Linux: bind to bridge IP only (more restrictive than 0.0.0.0)
janee serve --transport http --port 9100 --host 172.17.0.1Janee HTTP transport does NOT support:
- Bearer token authentication
- TLS/HTTPS
- Public IP exposure
- Cross-host networking
- Multi-tenant access control
Rationale: Janee is a single-user local tool, not a network secrets service.
If you need remote access, use SSH port forwarding:
ssh -L 9100:localhost:9100 user@host
# Then connect to localhost:9100For production multi-host deployments, consider a proper secrets service like HashiCorp Vault.
Error:
Error: connect ECONNREFUSED 172.17.0.1:9100
Fixes:
- Verify Janee is running:
ps aux | grep janee - Check port and host:
janee serve --transport http --port 9100 --host 0.0.0.0 - Test from container:
docker exec -it <container> nc -zv 172.17.0.1 9100 - Check firewall rules:
sudo iptables -L | grep 9100(Linux)
Error:
Could not resolve host: host.docker.internal
Fix: Add --add-host flag:
docker run --add-host=host.docker.internal:host-gateway ...Or use Docker Compose:
services:
agent:
extra_hosts:
- "host.docker.internal:host-gateway"Error:
Error: connect ETIMEDOUT
Fixes:
- Verify container can reach host network:
docker exec -it <container> ping 172.17.0.1 - Check Docker network:
docker network inspect bridge - Verify Janee is bound to correct interface:
netstat -tuln | grep 9100 - Check for conflicting port usage:
lsof -i :9100
Symptom: Container logs show spawn janee ENOENT
Cause: Plugin config doesn't have url field set.
Fix: Ensure your OpenClaw agent config includes:
config: {
url: "http://host.docker.internal:9100"
}Symptom: Connection to localhost:9100 works on host, fails from container
Cause: Container's localhost is its own network namespace, not the host's.
Fix: Use host.docker.internal (macOS/Windows) or bridge gateway IP (Linux).
One Janee instance can serve multiple containers:
version: '3'
services:
agent-1:
image: openclaw-agent:latest
extra_hosts:
- "host.docker.internal:host-gateway"
environment:
- JANEE_URL=http://host.docker.internal:9100
agent-2:
image: openclaw-agent:latest
extra_hosts:
- "host.docker.internal:host-gateway"
environment:
- JANEE_URL=http://host.docker.internal:9100All agents share the same API credentials and audit log.
Security implication: All containers can access all configured services. Use Docker network ACLs or separate Janee instances if isolation is needed.
- RFC-0004: Network Transport — Technical design document
- OpenClaw Plugin — Plugin source code
- MCP Specification — Protocol details