Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions social-images-manifest.json
Original file line number Diff line number Diff line change
Expand Up @@ -105,8 +105,8 @@
"imageUrl": "https://hcti.io/v1/image/292fbcccd9914a9c91a0738a6761c5e415c793b6e3d97a3b282f6ba340486bb7"
},
"deployment/exposure-modes": {
"hash": "e8baf14472f7f6848d6f325662cfaaa8e5c218eb0c503a22021e748f5d6a7969",
"imageUrl": "https://hcti.io/v1/image/e8df67e916d7e662c134601345647d510b2b90f2af1b85537817761cb4efc698"
"hash": "d18cf6800d78805419d7324432070556d829d05997a231f786d93193f5e970ad",
"imageUrl": "https://hcti.io/v1/image/7ddfb5e506a8c2c157d85ec9a438cc8ceda6a6eda0fe876428895f70f55df6ce"
},
"deployment/systemd": {
"hash": "8d2c632b152b487fe516506b4120ae564770130dae5cbe524830ee01f86006cd",
Expand Down
22 changes: 15 additions & 7 deletions src/content/docs/cli/init.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ title: "netclaw init"
description: "Interactive setup wizard for providers, channels, security, and network exposure."
---

First-run wizard. Configures your provider, security policy, channels, identity, skills, and network exposure in one pass, then starts the daemon.
Interactive first-run setup. Configures your provider, security policy, channels, identity, skills, and network exposure in one pass, then starts the daemon.

## Usage

Expand All @@ -25,11 +25,12 @@ Have these ready before starting:
- **Slack tokens** (if using Slack) — Bot Token (`xoxb-...`) + App Token (`xapp-...`). See the [Slack quickstart](https://api.slack.com/start/quickstart)
- **Discord bot token** (if using Discord) — from the [Discord developer portal](https://discord.com/developers/docs/getting-started)

No other dependencies needed.
For local-only setup, that is enough. For non-local exposure modes, you may also need `tailscaled`, `cloudflared`, or a working reverse proxy depending on the mode you choose.


## Wizard steps

The wizard adapts to your choices — steps get skipped based on your security posture and feature selections.
The wizard skips steps based on your choices, security posture, and feature selections.

### 1. LLM Provider

Expand Down Expand Up @@ -124,11 +125,12 @@ Subscribe to skill feeds — curated skill collections from the community or you
| Mode | Reachability | Requires |
|------|-------------|----------|
| `local` | Loopback only (this machine) | Nothing |
| `reverse-proxy` | Whatever your proxy exposes | Reverse proxy + trusted proxy list |
| `tailscale-serve` | Your [Tailscale](https://tailscale.com/kb/) tailnet | `tailscaled` running |
| `tailscale-funnel` | Public internet via Tailscale | `tailscaled` running |
| `cloudflare-tunnel` | Public internet via [Cloudflare Tunnel](https://developers.cloudflare.com/cloudflare-one/connections/connect-networks/) | `cloudflared` running |

The internet-facing modes (`tailscale-funnel`, `cloudflare-tunnel`) make you type an explicit confirmation. They're not kidding about the warning.
The internet-facing modes (`tailscale-funnel`, `cloudflare-tunnel`) make you type an explicit confirmation because they expose the daemon to the internet.

![Webhook configuration](/screenshots/output/init-09-webhooks.png)

Expand All @@ -138,20 +140,25 @@ If you enabled webhooks, you'll configure inbound routes here.

![Health check running](/screenshots/output/init-10-health-check.png)

Validates config files, tests provider connectivity, verifies channel tokens, checks tunnel prerequisites.
Validates config files, tests provider connectivity, verifies channel tokens, and checks tunnel or reverse-proxy prerequisites.

![Health check complete](/screenshots/output/init-10-health-check-complete.png)

All green? The daemon starts automatically.
If all checks pass, the daemon starts automatically.

If you picked a non-local exposure mode, the first successful daemon start also keeps a bootstrap pairing path available so the local CLI can finish remote-auth setup.

If something fails, the wizard tells you which check broke, shows exposure-mode validation failures directly, and suggests running `netclaw doctor` for detailed diagnostics.

If something fails, the wizard tells you which check broke and suggests running `netclaw doctor` for detailed diagnostics.
If `netclaw init` fails partway through, the files it already wrote stay on disk. It is safe to rerun `netclaw init`, or inspect the saved config and use `netclaw doctor` before trying again.

## What it creates

| File | Purpose |
|------|---------|
| `~/.netclaw/config/netclaw.json` | Main configuration (includes security posture) |
| `~/.netclaw/config/secrets.json` | Encrypted credentials |
| `~/.netclaw/config/devices.json` | Paired device registry, including first-launch bootstrap device when needed |
| `~/.netclaw/identity/` | Agent identity and personality |

## After init
Expand Down Expand Up @@ -180,3 +187,4 @@ netclaw chat
- [Slack Socket Mode](https://api.slack.com/apis/socket-mode) — How netclaw connects to Slack without a public endpoint
- [Tailscale Funnel documentation](https://tailscale.com/kb/1223/funnel/) — Exposing services to the public internet via Tailscale
- [Cloudflare Tunnel documentation](https://developers.cloudflare.com/cloudflare-one/connections/connect-networks/) — Exposing services via Cloudflare's network
- [Traefik reverse proxy docs](https://doc.traefik.io/traefik/routing/routers/) — reverse-proxy option if you're exposing netclaw behind Traefik
26 changes: 22 additions & 4 deletions src/content/docs/deployment/docker.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ title: "Docker Deployment"
description: "Run the netclaw daemon in a Docker container with persistent config, health checks, and zero-downtime upgrades."
---

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.
The netclaw Docker image runs the daemon (`netclawd`) in a supervised container. The CLI can stay on your host or run inside the container with `docker exec`. By default the local control-plane endpoint is `127.0.0.1:5199` when you publish it that way; non-local exposure modes add more auth and proxy rules.

## Before you begin

Expand All @@ -13,15 +13,18 @@ The netclaw Docker image runs the daemon (`netclawd`) in a supervised container.

## Quick start

This path assumes you already have an initialized `~/.netclaw` directory.

```bash
docker run -d \
--name netclaw \
-v ~/.netclaw:/root/.netclaw \
-p 127.0.0.1:5199:5199 \
-e NETCLAW_Daemon__Host=0.0.0.0 \
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.
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. `NETCLAW_Daemon__Host=0.0.0.0` makes the daemon listen on the container interface so Docker's published port can reach it. The volume mount persists identity, config, credentials, session state, and logs across restarts. Self-update is disabled in the image. Use the image tag as 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.

Expand All @@ -43,6 +46,8 @@ docker exec -it netclaw netclaw init

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

If you choose a non-local exposure mode during first-run setup, netclaw now seeds a one-shot local bootstrap credential before the first successful non-local daemon start. That prevents first boot from getting stuck waiting on pairing.

## Configuration via environment variables

Pass provider credentials and model config as `NETCLAW_`-prefixed environment variables. Double underscores separate path segments, following the [.NET configuration convention](https://learn.microsoft.com/en-us/dotnet/core/extensions/configuration-providers#environment-variable-configuration-provider). Env vars take highest priority, overriding both `netclaw.json` and `secrets.json`.
Expand All @@ -52,6 +57,7 @@ docker run -d \
--name netclaw \
-v ~/.netclaw:/root/.netclaw \
-p 127.0.0.1:5199:5199 \
-e NETCLAW_Daemon__Host=0.0.0.0 \
-e NETCLAW_Providers__openrouter__Type=openrouter \
-e NETCLAW_Providers__openrouter__ApiKey=sk-or-v1-... \
-e NETCLAW_Models__Main__Provider=openrouter \
Expand All @@ -78,6 +84,7 @@ services:
volumes:
- netclaw-home:/root/.netclaw
environment:
NETCLAW_Daemon__Host: 0.0.0.0
NETCLAW_Providers__local-ollama__Type: ollama
NETCLAW_Providers__local-ollama__Endpoint: http://ollama:11434
NETCLAW_Models__Main__Provider: local-ollama
Expand Down Expand Up @@ -108,6 +115,8 @@ 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.

`qwen3:30b` is a large model. For first-time testing on modest hardware, pick a smaller Ollama model.

### Docker socket access

If you want the agent to manage Docker containers as part of its tool use, mount the socket:
Expand All @@ -118,6 +127,8 @@ If you want the agent to manage Docker containers as part of its tool use, mount

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

Treat this as host-level access. A process that can talk to the Docker socket can usually control the host.

## Volume layout

Everything the daemon persists lives under `/root/.netclaw`:
Expand All @@ -137,7 +148,7 @@ Everything the daemon persists lives under `/root/.netclaw`:
└── logs/ # crash-*.log, session logs
```

Back up this volume before upgrades. `config/` and `identity/` are the critical directories; everything else can be regenerated.
Back up this volume before upgrades. `config/` and `identity/` are the critical directories; everything else can be regenerated. If you use a bind mount, copy `~/.netclaw` directly. If you use a named volume, export it with your normal Docker volume backup process before upgrades.

## Health checks

Expand All @@ -163,6 +174,8 @@ 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.

That also helps with pairing: if the daemon is running in a container and you need a daemon-host bootstrap or recovery path, `docker exec netclaw netclaw daemon pair` works the same way as running it on a bare-metal daemon host.

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

## Upgrading
Expand All @@ -181,6 +194,7 @@ docker run -d \
--name netclaw \
-v ~/.netclaw:/root/.netclaw \
-p 127.0.0.1:5199:5199 \
-e NETCLAW_Daemon__Host=0.0.0.0 \
ghcr.io/netclaw-dev/netclaw:latest

# Wait for readiness
Expand Down Expand Up @@ -221,6 +235,8 @@ ss -tlnp | grep 5199
docker logs netclaw
```

If the container is configured for `reverse-proxy`, also check whether the daemon is still bound to loopback. Reverse-proxy mode rejects loopback final-hop topologies.

### Container keeps restarting

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`.
Expand All @@ -232,14 +248,16 @@ The 30-second start period gives the daemon time to initialize. If it's still un
## Related pages

- [Models](/configuration/models/) — model slot configuration
- [Exposure Modes](/deployment/exposure-modes/) — remote access via Tailscale or Cloudflare Tunnel
- [Exposure Modes](/deployment/exposure-modes/) — remote access via reverse proxy, Tailscale, or Cloudflare Tunnel
- [systemd Service](/deployment/systemd/) — bare-metal Linux alternative
- [OpenTelemetry](/observability/opentelemetry/) — daemon metrics and log export

## Resources

- [Docker Engine installation guide](https://docs.docker.com/engine/install/) — platform-specific install instructions
- [Docker Compose documentation](https://docs.docker.com/compose/) — multi-container orchestration
- [Docker security guide](https://docs.docker.com/engine/security/) — baseline guidance for socket mounts and daemon exposure
- [GitHub Container Registry (GHCR)](https://docs.github.com/en/packages/working-with-a-github-packages-registry/working-with-the-container-registry) — pulling and authenticating with ghcr.io
- [.NET environment variable configuration](https://learn.microsoft.com/en-us/dotnet/core/extensions/configuration-providers#environment-variable-configuration-provider) — the double-underscore nesting convention
- [Docker exec reference](https://docs.docker.com/reference/cli/docker/container/exec/) — run CLI commands inside a live container
- [Ollama model library](https://ollama.com/library) — browse available models for local inference
Loading
Loading