Skip to content

Docker Deployment

The netclaw Docker image runs the daemon (netclawd) in a supervised container. The CLI stays on your host and connects over HTTP at 127.0.0.1:5199. Your interactive terminal stays outside the container; the daemon runs headless.

  • Docker Engine 20.10+ or Docker Desktop
  • A provider API key (OpenRouter, Anthropic, OpenAI, etc.) or a reachable Ollama instance
  • An initialized ~/.netclaw directory — run netclaw init on the host first, or bind-mount a pre-configured one. If you don’t have the CLI yet, see Installation.
Terminal window
docker run -d \
--name netclaw \
-v ~/.netclaw:/root/.netclaw \
-p 127.0.0.1:5199:5199 \
ghcr.io/netclaw-dev/netclaw

The port binding is loopback-only (127.0.0.1:5199) because the health check endpoint is unauthenticated — don’t expose it to the network. The volume mount persists identity, config, credentials, session state, and logs across restarts. Self-update is disabled in the image; the image tag is the version. Update availability checks still run, so you’ll know when a new release exists.

Tags: :latest tracks the most recent release. Pin to a version tag (e.g., :1.2.3) in production.

Verify from the host:

Terminal window
netclaw status

The CLI defaults to http://127.0.0.1:5199, so no configuration is needed for local Docker. For remote daemons, see Exposure Modes.

If you don’t have netclaw init on the host, run it inside the container:

Terminal window
docker exec -it netclaw netclaw init

The interactive wizard works the same way over docker exec -it.

Pass provider credentials and model config as NETCLAW_-prefixed environment variables. Double underscores separate path segments, following the .NET configuration convention. Env vars take highest priority, overriding both netclaw.json and secrets.json.

Terminal window
docker run -d \
--name netclaw \
-v ~/.netclaw:/root/.netclaw \
-p 127.0.0.1:5199:5199 \
-e NETCLAW_Providers__openrouter__Type=openrouter \
-e NETCLAW_Providers__openrouter__ApiKey=sk-or-v1-... \
-e NETCLAW_Models__Main__Provider=openrouter \
-e NETCLAW_Models__Main__ModelId=anthropic/claude-sonnet-4 \
ghcr.io/netclaw-dev/netclaw

Keep secrets out of config files — inject them at runtime. The ModelId value must match a valid identifier from the provider API; see Models for the full schema and available model IDs.

For anything beyond quick testing, use Compose. This example pairs netclaw with a local Ollama instance and uses named volumes (unlike the bind mount in the quick start) for easier lifecycle management:

services:
netclaw:
image: ghcr.io/netclaw-dev/netclaw
container_name: netclaw
restart: unless-stopped
depends_on:
- ollama
ports:
- "127.0.0.1:5199:5199"
volumes:
- netclaw-home:/root/.netclaw
environment:
NETCLAW_Providers__local-ollama__Type: ollama
NETCLAW_Providers__local-ollama__Endpoint: http://ollama:11434
NETCLAW_Models__Main__Provider: local-ollama
NETCLAW_Models__Main__ModelId: qwen3:30b
ollama:
image: ollama/ollama:latest
container_name: ollama
ports:
- "127.0.0.1:11434:11434"
volumes:
- ollama-data:/root/.ollama
volumes:
netclaw-home:
ollama-data:
Terminal window
docker compose up -d

Pull the model into Ollama before netclaw can use it:

Terminal window
docker exec ollama ollama pull qwen3:30b

Netclaw references Ollama by service name (http://ollama:11434) since Compose puts both containers on the same network.

If you want the agent to manage Docker containers as part of its tool use, mount the socket:

Terminal window
-v /var/run/docker.sock:/var/run/docker.sock

Add this to the volumes section of the netclaw service in your Compose file or to the docker run command.

Everything the daemon persists lives under /root/.netclaw:

/root/.netclaw/
├── client/config.json # CLI endpoint state
├── config/
│ ├── netclaw.json # Daemon settings
│ └── secrets.json # Credentials
├── identity/ # Agent personality (SOUL.md, AGENTS.md, TOOLING.md)
├── sessions/ # Conversation history
├── keys/ # Key material
├── projects/
├── environment/
├── schedules/
└── logs/ # crash-*.log, session logs

Back up this volume before upgrades. config/ and identity/ are the critical directories; everything else can be regenerated.

The image has a built-in health check that polls every 15 seconds with a 30-second startup grace period:

HEALTHCHECK --interval=15s --timeout=5s --start-period=30s --retries=3
CMD curl -sf http://127.0.0.1:5199/api/health/ready || exit 1
EndpointAuthPurpose
GET /api/health/readyNoneReturns 200 OK when the daemon is ready. Use this for orchestrators and load balancers.
GET /api/health/statusRequiredReturns detailed runtime status.

Check container health from the host:

Terminal window
docker inspect --format='{{.State.Health.Status}}' netclaw

The entrypoint script is a PID 1 supervisor. If the daemon exits (config-update restart, crash, netclaw init wizard completion), the entrypoint waits 2 seconds and restarts it. The container stays alive, so docker exec sessions survive daemon restarts.

docker stop sends SIGTERM, which the entrypoint forwards to the daemon for a clean shutdown. Docker’s default 10-second stop timeout is plenty.

Self-update is disabled in the image (NETCLAW_Daemon__DisableSelfUpdate=true), so upgrades mean pulling a new image. Schema migrations are forward-only with no automatic rollback.

Terminal window
# Pull the new version
docker pull ghcr.io/netclaw-dev/netclaw:latest
# Stop the old container (volume stays)
docker stop netclaw && docker rm netclaw
# Start with the new image
docker run -d \
--name netclaw \
-v ~/.netclaw:/root/.netclaw \
-p 127.0.0.1:5199:5199 \
ghcr.io/netclaw-dev/netclaw:latest
# Wait for readiness
until curl -sf http://127.0.0.1:5199/api/health/ready; do sleep 2; done
echo "Daemon is ready"

With Compose:

Terminal window
docker compose pull
docker compose up -d

To rollback, stop the container and start with the previous image tag. If the new version already ran a schema migration, restore the volume from backup to roll back.

PropertyValue
Registryghcr.io/netclaw-dev/netclaw
Baseubuntu:24.04
Architectureslinux/amd64, linux/arm64
Port5199
Volume/root/.netclaw
LicenseApache-2.0

Built on Ubuntu 24.04 (not a minimal runtime), the image ships with git, jq, sqlite3, python3, curl, wget, gh, and more. Operators can apt-get install additional tools if the agent needs them.

Confirm the port mapping binds to 127.0.0.1 and nothing else is on port 5199:

Terminal window
ss -tlnp | grep 5199
docker logs netclaw

The entrypoint restarts the daemon on every exit, and that’s by design. If it’s a crash loop, check docker logs netclaw for the cause. Common culprits: missing provider config, invalid API key, or a required field missing from netclaw.json.

The 30-second start period gives the daemon time to initialize. If it’s still unhealthy after that, the daemon isn’t starting. Check logs and run netclaw doctor from the host, or docker exec netclaw netclaw doctor inside the container.