Deploying wigolo using Docker for Self-Hosting: Complete Setup Guide
Deploy wigolo by pulling the official image ghcr.io/knockoutez/wigolo, mounting a persistent volume at /data, setting a secure WIGOLO_API_TOKEN, and running the container with the serve command bound to 0.0.0.0:3333 using the Docker Compose configuration in packaging/compose.serve.yml.
wigolo is an open-source Node.js daemon that powers AI agents through both MCP (stdio) and HTTP REST interfaces. According to the KnockOutEZ/wigolo repository source code, the project provides a multi-stage Dockerfile with default (slim) and full targets, enabling flexible self-hosting strategies from ephemeral containers to persistent production daemons.
Choose Your Deployment Mode
The repository supports three distinct Docker deployment patterns based on your infrastructure requirements:
- One-off stdio client: Use
docker run -i --rmfor quick, stateless tasks where the container exits after completion. The Chromium browser and models download on first use into the mounted volume. - Persistent HTTP daemon: Run via Docker Compose for long-running services that expose REST endpoints to multiple clients. This mode binds to
0.0.0.0inside the container and includes health checks defined inpackaging/compose.serve.yml. - Full image (pre-installed browser): Build with
--target fullto embed the Chromium binary directly in the image, eliminating volume dependencies for--rmscenarios or read-only filesystems.
Pull the Docker Image
Start by fetching the latest slim image from the GitHub Container Registry:
docker pull ghcr.io/knockoutez/wigolo
This pulls the default (slim) target. The image remains lightweight because the browser binary and on-device models are cached on first use rather than baked into the layers, as specified in the root Dockerfile.
Configure Data Persistence
Create a named Docker volume to persist data across container restarts:
docker volume create wigolo-data
The Dockerfile declares VOLUME ["/data"], mounting this directory inside the container. This location stores the Chromium binary, on-device models, encrypted keys, and cache files, ensuring they survive image updates and container recreation.
Set Up Authentication
The wigolo daemon implements a fail-closed security model: it refuses to bind to non-loopback interfaces unless authentication is configured. Generate a secure random token:
export WIGOLO_API_TOKEN=$(openssl rand -hex 32)
For production deployments, avoid passing tokens via environment variables directly. Instead, use the WIGOLO_API_TOKEN_FILE option to mount a secret file, as demonstrated in the packaging/compose.serve.yml configuration.
Launch with Docker Compose
For production-grade self-hosting, use the provided Compose file which includes health checks and proper networking:
docker compose -f packaging/compose.serve.yml up -d
The packaging/compose.serve.yml file defines several critical configurations:
- Command: Executes
["serve","--host","0.0.0.0","--port","3333"]to expose the daemon to external traffic - Port mapping: Binds host port
3333to container port3333 - Environment: Sets
WIGOLO_DATA_DIR=/dataand optionally injectsWIGOLO_API_TOKEN - Healthcheck: Probes the
/healthendpoint (defined at lines 49-58) to monitor daemon readiness
To customize authentication, edit the compose file to uncomment either:
WIGOLO_API_TOKEN: "your-secure-random-token"
Or the more secure secret file approach:
WIGOLO_API_TOKEN_FILE: /run/secrets/wigolo_token
Verify and Access the Service
Confirm the container is healthy by querying the health endpoint:
curl -s http://localhost:3333/health
A 200 OK response indicates the Node.js daemon is operational. The Docker Compose health check will automatically restart the container if this endpoint returns unhealthy status codes.
Once running, wigolo exposes two primary interfaces on port 3333:
- MCP endpoint:
http://localhost:3333/mcpfor stdio-based agent communication - REST API:
http://localhost:3333/v1/...for HTTP-based interactions
All requests must include the bearer token in the Authorization header:
curl -H "Authorization: Bearer $WIGOLO_API_TOKEN" \
-X POST -d '{"query":"example search"}' \
http://localhost:3333/v1/search
Running Behind a Reverse Proxy
If you run wigolo behind a reverse proxy (such as Nginx or Traefik) that handles authentication, disable the internal token requirement by setting:
WIGOLO_SERVE_ALLOW_UNAUTHENTICATED: "1"
Only enable this when your external proxy enforces strict authentication, as the daemon will accept anonymous requests from any source when this variable is set.
Update wigolo
When new versions are released, update without losing cached data:
docker pull ghcr.io/knockoutez/wigolo
docker compose -f packaging/compose.serve.yml up -d --force-recreate
The wigolo-data volume persists the browser binary and model files, so only the application code updates while the cache remains intact.
Build the Full Image Target
For environments where volume mounts are impossible, build the full target which embeds Chromium:
docker build --target full -t wigolo:full .
docker run -i --rm -p 3333:3333 \
-e WIGOLO_API_TOKEN=$WIGOLO_API_TOKEN \
wigolo:full serve --host 0.0.0.0 --port 3333
This approach, defined in the root Dockerfile, produces a larger image but executes immediately without downloading dependencies, making it ideal for ephemeral CI/CD pipelines or restricted filesystems.
Summary
- Pull the slim image from
ghcr.io/knockoutez/wigolofor standard deployments, or build thefulltarget for volume-less execution - Mount a persistent volume at
/datato cache the Chromium binary, models, and encrypted keys across restarts - Secure the daemon by setting
WIGOLO_API_TOKENwhen binding to non-loopback interfaces, or useWIGOLO_API_TOKEN_FILEfor production secrets management - Deploy using
packaging/compose.serve.ymlfor automated health checks and proper port exposure on0.0.0.0:3333 - Verify deployment via the
/healthendpoint before routing production traffic
Frequently Asked Questions
What is the difference between the slim and full Docker images?
The slim image (default) downloads the Chromium browser binary and on-device models on first use, storing them in the /data volume. This keeps the initial image size small but requires a writable volume. The full image, built by targeting docker build --target full, embeds the browser binary directly into the image layers according to the Dockerfile specification, making it suitable for ephemeral containers or environments where volume mounts are restricted, though it results in a significantly larger download size.
Why does wigolo require an API token for Docker deployments?
According to the source code implementation in the KnockOutEZ/wigolo repository, the daemon refuses to start on non-loopback interfaces (0.0.0.0) unless the WIGOLO_API_TOKEN environment variable or WIGOLO_API_TOKEN_FILE secret is provided. This fail-closed security model prevents accidental exposure of the MCP and REST endpoints to untrusted networks. When running behind a reverse proxy that handles authentication, you can disable this requirement by setting WIGOLO_SERVE_ALLOW_UNAUTHENTICATED=1.
How do I persist data when updating the wigolo container?
Create a named Docker volume (e.g., wigolo-data) and mount it at /data inside the container as specified in the Dockerfile (VOLUME ["/data"]). When updating images using docker pull and recreating containers with docker compose up -d --force-recreate, attach the same volume to the new container instance. The browser binary, cached models, and encrypted keys stored in /data remain intact across updates.
Where is the Docker Compose configuration located in the repository?
The production-ready Docker Compose configuration is located at packaging/compose.serve.yml in the KnockOutEZ/wigolo repository. This file includes the recommended command arguments (serve --host 0.0.0.0 --port 3333), health check definitions probing the /health endpoint, and example configurations for both environment variable and file-based secret injection appropriate for self-hosting deployments.
Have a question about this repo?
These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:
curl -s "https://instagit.com/install.md" Maintain an open-source project? Get it listed too →