# How to Configure Wigolo for Self-Hosting with Docker and Secure Token Authentication

> Self-host Wigolo using Docker. Configure token authentication, bind the daemon to 0.0.0.0, and persist data for secure, reliable operation.

- Repository: [Towhid Khan/wigolo](https://github.com/KnockOutEZ/wigolo)
- Tags: how-to-guide
- Published: 2026-07-19

---

**To self-host Wigolo in Docker, you must bind the daemon to `0.0.0.0`, provide a bearer token via `WIGOLO_API_TOKEN` or `WIGOLO_API_TOKEN_FILE`, and persist the `/data` directory to survive container restarts.**

Wigolo is an open-source Node.js MCP (Model Context Protocol) server that exposes either a local stdio interface or an HTTP daemon. When configuring Wigolo for self-hosting with Docker and secure token authentication, the service follows a strict *fail-closed* security model: it refuses to start on non-loopback addresses unless authentication is explicitly configured. This guide covers the official deployment patterns using the repository's provided compose files and environment variable conventions.

## Understanding the Security Model and Binding Requirements

Wigolo's daemon operates in two modes: **stdio** for local MCP clients and **serve** for HTTP-based remote access. When you deploy in Docker, you must expose the service beyond localhost using `--host 0.0.0.0`. According to the source code in [`docs/self-hosting.md`](https://github.com/KnockOutEZ/wigolo/blob/main/docs/self-hosting.md) (lines 34-44), the application enforces a critical safety check: if the bind address is not loopback (`127.0.0.1` or `localhost`), the daemon validates that a bearer token is configured. If no token is present, the process exits immediately to prevent accidental unsecured exposure.

## Docker Deployment Options

The repository provides two primary methods for containerized deployment: Docker Compose for production stability and `docker run` for quick testing.

### Using Docker Compose (Recommended)

The official compose file at [`packaging/compose.serve.yml`](https://github.com/KnockOutEZ/wigolo/blob/main/packaging/compose.serve.yml) defines the standard production configuration. It specifies the image `ghcr.io/knockoutez/wigolo`, exposes port **3333**, and mounts a named volume to `/data` for persistence.

Key configuration elements from [`packaging/compose.serve.yml`](https://github.com/KnockOutEZ/wigolo/blob/main/packaging/compose.serve.yml) (lines 35-40) include:

- **Port mapping**: Exposes container port 3333 to the host
- **Volume persistence**: Uses a named Docker volume for `/data` to store on-device models, browser binaries, and cache between restarts
- **Health checks**: Built-in HTTP health endpoint monitoring

To deploy:

```bash
docker compose -f packaging/compose.serve.yml up -d

```

### Using Docker Run (Quick Start)

For immediate testing without Compose, generate a secure random token and launch the container directly:

```bash

# Generate a 32-byte hex token

TOKEN=$(openssl rand -hex 32)

docker run -d \
  -p 3333:3333 \
  -v wigolo-data:/data \
  -e WIGOLO_API_TOKEN=$TOKEN \
  ghcr.io/knockoutez/wigolo \
  serve --host 0.0.0.0 --port 3333

```

The `--host 0.0.0.0` flag is mandatory for Docker networking, allowing the container to accept connections from outside its network namespace.

## Configuring Authentication

Wigolo supports two methods for supplying the bearer token: inline environment variables for development and secret files for production security.

### Inline Token Configuration (WIGOLO_API_TOKEN)

Set the `WIGOLO_API_TOKEN` environment variable when starting the container. Every request to REST endpoints (`/v1/*`) or the MCP endpoint (`/mcp`) must include the header:

```

Authorization: Bearer <token>

```

Example API call:

```bash
curl -H "Authorization: Bearer $TOKEN" \
     http://localhost:3333/v1/search \
     -d '{"query":"latest JavaScript async patterns"}' \
     -H "Content-Type: application/json"

```

### Secret File Configuration (WIGOLO_API_TOKEN_FILE)

For production deployments, avoid exposing tokens in environment variables where they might leak via `docker inspect` or process listings. Instead, use the `WIGOLO_API_TOKEN_FILE` variable to reference a mounted secret file.

As implemented in [`packaging/compose.serve.yml`](https://github.com/KnockOutEZ/wigolo/blob/main/packaging/compose.serve.yml) (lines 42-45), bind-mount a secret file and reference it:

```bash

# Create secret file outside version control

echo "$TOKEN" > /run/secrets/wigolo_token

# Mount and configure

docker run -d \
  -p 3333:3333 \
  -v wigolo-data:/data \
  -v /run/secrets/wigolo_token:/run/secrets/wigolo_token:ro \
  -e WIGOLO_API_TOKEN_FILE=/run/secrets/wigolo_token \
  ghcr.io/knockoutez/wigolo \
  serve --host 0.0.0.0 --port 3333

```

This pattern keeps the token out of the container's environment table while maintaining the same authentication requirements.

## Building the Docker Image

The `Dockerfile` in the repository root defines two build targets:

1. **default** (slim): Contains the Node.js runtime but downloads the browser binary on first use into the persisted `/data` volume
2. **full**: Pre-installs the browser binary for air-gapped or latency-sensitive environments

According to `Dockerfile` (lines 5-10 and 62-66), the default target is sufficient for most self-hosting scenarios. The first request triggers a lazy download of the browser binary into `/data`, which survives container restarts thanks to the volume mount.

To build the full image locally:

```bash
docker build --target full -t wigolo:full .

```

## Connecting Clients to the Secured Endpoint

Once the container is running with token authentication, configure MCP-compatible agents to connect using the base URL and token:

```bash
wigolo config --set baseUrl=http://<host>:3333
wigolo config --set apiToken=$TOKEN

```

The agent will automatically include the `Authorization: Bearer` header when communicating with the `/mcp` endpoint. For direct REST API integration, always include the authorization header explicitly as shown in previous examples.

## Summary

- **Fail-closed security**: Wigolo refuses to start on `0.0.0.0` without a bearer token configured via `WIGOLO_API_TOKEN` or `WIGOLO_API_TOKEN_FILE`
- **Docker Compose**: Use [`packaging/compose.serve.yml`](https://github.com/KnockOutEZ/wigolo/blob/main/packaging/compose.serve.yml) for production deployments with built-in volume persistence and health checks
- **Token methods**: Use inline `WIGOLO_API_TOKEN` for development; use `WIGOLO_API_TOKEN_FILE` with bind-mounted secrets for production to avoid leaking credentials via `docker inspect`
- **Data persistence**: Always mount a volume to `/data` to preserve browser binaries, models, and cache across container restarts
- **Image variants**: The default image downloads the browser on first use; the full target pre-bundles it for offline environments

## Frequently Asked Questions

### Why does Wigolo refuse to start when I bind to 0.0.0.0?

Wigolo implements a fail-closed security model as documented in [`docs/self-hosting.md`](https://github.com/KnockOutEZ/wigolo/blob/main/docs/self-hosting.md). When the daemon detects a non-loopback bind address (`0.0.0.0` or any external IP), it validates that authentication is configured. Without `WIGOLO_API_TOKEN` or `WIGOLO_API_TOKEN_FILE` set, the process exits immediately to prevent accidental exposure of an unsecured service to the network.

### How do I prevent my API token from appearing in docker inspect output?

Use the `WIGOLO_API_TOKEN_FILE` environment variable instead of `WIGOLO_API_TOKEN`. Store your token in a file on the host (e.g., `/run/secrets/wigolo_token`), bind-mount it as a read-only volume, and set `WIGOLO_API_TOKEN_FILE` to the container path. This keeps the secret out of the container's environment variables, preventing exposure through `docker inspect` or process enumeration.

### What is the difference between the default and full Docker image targets?

The **default** target (defined in `Dockerfile` lines 5-10) provides a slim image that downloads the browser binary on first request into the persisted `/data` volume. The **full** target (lines 62-66) pre-installs the browser binary during the build process. Use the default target for standard deployments with internet access; use the full target for air-gapped environments or to eliminate first-request latency.

### How do I persist data across container restarts?

Mount a named Docker volume to the `/data` directory inside the container. This directory stores the browser binary, on-device models, and cache. The official [`packaging/compose.serve.yml`](https://github.com/KnockOutEZ/wigolo/blob/main/packaging/compose.serve.yml) configures this automatically with `volumes: wigolo-data:/data`. When using `docker run`, include `-v wigolo-data:/data` to ensure persistence.