Docker Deployment
LumaBrowser Docker packages the full browser automation platform into a self-hosted container. It runs a lightweight Linux desktop with LumaBrowser, exposing the REST API, MCP tools, and a web-based visual desktop via your browser.
Docker deployment requires an Enterprise Fleet license with the HEADLESS_DEPLOY entitlement. Get a license →
- Docker 20.10+ with Docker Compose v2
- Enterprise Fleet license from lumabyte.com/pricing
- 2 GB+ RAM allocated to the container (Chromium requires adequate shared memory)
- Network access to
api.keygen.shfor license validation on startup
1. Create a .env file
LUMA_LICENSE_KEY=your-enterprise-license-key
LUMA_VNC_PASSWORD=your-secure-password
2. Run with Docker Compose
docker compose up -d
3. Access LumaBrowser
| Service | URL | Description |
|---|---|---|
| Web Desktop | http://localhost:6080 | Visual browser desktop via noVNC |
| REST API | http://localhost:3000/api/health | Health check and API access |
| MCP Tools | http://localhost:3000/api/mcp/tools | Available MCP tool listing |
4. Verify
# Check the API is responding
curl http://localhost:3000/api/health
# List available MCP tools
curl http://localhost:3000/api/mcp/tools
# View container logs
docker logs lumabrowser
Required
| Variable | Description |
|---|---|
required LUMA_LICENSE_KEY |
Enterprise Fleet license key from Keygen.sh. The container will not start without a valid key with the HEADLESS_DEPLOY entitlement. |
required LUMA_VNC_PASSWORD |
Password for the web-based desktop access. Required for secure VNC connections. |
Optional
| Variable | Default | Description |
|---|---|---|
optional LUMA_API_PORT |
3000 |
REST API port inside the container |
optional LUMA_VNC_PORT |
6080 |
noVNC web desktop port inside the container |
optional LUMA_DATA_DIR |
/data |
Persistent data directory mount point |
optional LUMA_MACHINE_ID |
container hostname | Stable machine fingerprint for license activation. Set this to persist the same machine ID across container restarts. |
Configure LLM providers via environment variables so AI features (AI Chat, Template Builder, Timed Tasks) work immediately on startup.
OpenAI-Compatible (LM Studio, Ollama, vLLM)
| Variable | Example | Description |
|---|---|---|
LUMA_LLM_PROVIDER | openai | Set the active provider |
LUMA_OPENAI_ENDPOINT | http://host.docker.internal:1234 | OpenAI-compatible API base URL |
LUMA_OPENAI_KEY | lm-studio | API key (use any value for LM Studio) |
LUMA_OPENAI_MODEL | qwen2.5-7b-instruct | Default model to use |
Anthropic (Claude)
| Variable | Example | Description |
|---|---|---|
LUMA_LLM_PROVIDER | anthropic | Set the active provider |
LUMA_ANTHROPIC_KEY | sk-ant-... | Anthropic API key |
LUMA_ANTHROPIC_MODEL | claude-sonnet-4-6-20250514 | Default Claude model |
LUMA_ANTHROPIC_ENDPOINT | https://api.anthropic.com | API endpoint (default works for most) |
Example: LM Studio on Host Machine
# .env file
LUMA_LICENSE_KEY=your-enterprise-key
LUMA_VNC_PASSWORD=secret123
LUMA_LLM_PROVIDER=openai
LUMA_OPENAI_ENDPOINT=http://host.docker.internal:1234
LUMA_OPENAI_KEY=lm-studio
LUMA_OPENAI_MODEL=qwen2.5-7b-instruct
Use host.docker.internal to reach services running on the Docker host machine (e.g., LM Studio, Ollama).
LumaBrowser stores all settings, templates, network watchers, and license cache in a SQLite database at /data/settings.db. Mount a volume to persist data across container restarts.
volumes:
- luma-data:/data
Shared Volumes (Multi-Instance)
Multiple containers can share the same data volume. SQLite WAL mode supports concurrent readers, and a 5-second busy timeout handles write contention gracefully.
Note: For deployments with heavy write workloads, use separate volumes per instance to avoid contention.
Using Docker Run
docker run -d \
-e LUMA_LICENSE_KEY=your-enterprise-key \
-e LUMA_VNC_PASSWORD=your-password \
-p 3000:3000 \
-p 6080:6080 \
-v luma-data:/data \
--shm-size=2g \
--name lumabrowser \
lumabyte/lumabrowser:latest
Using Docker Compose
docker compose up -d
See Docker Compose Reference for the full configuration file.
Run multiple LumaBrowser instances behind a single Enterprise Fleet license. Each instance activates a floating machine slot. Use offset ports to avoid conflicts.
# docker-compose.multi.yml
services:
lumabrowser-1:
build: { context: ., dockerfile: docker/Dockerfile }
environment:
- LUMA_LICENSE_KEY=${LUMA_LICENSE_KEY}
- LUMA_VNC_PASSWORD=${LUMA_VNC_PASSWORD}
ports:
- "3001:3000"
- "6081:6080"
volumes:
- shared-data:/data
shm_size: '2gb'
lumabrowser-2:
build: { context: ., dockerfile: docker/Dockerfile }
environment:
- LUMA_LICENSE_KEY=${LUMA_LICENSE_KEY}
- LUMA_VNC_PASSWORD=${LUMA_VNC_PASSWORD}
ports:
- "3002:3000"
- "6082:6080"
volumes:
- shared-data:/data
shm_size: '2gb'
volumes:
shared-data:
docker compose -f docker-compose.multi.yml up -d
# docker-compose.yml
services:
lumabrowser:
build:
context: .
dockerfile: docker/Dockerfile
environment:
# Required
- LUMA_LICENSE_KEY=${LUMA_LICENSE_KEY}
- LUMA_VNC_PASSWORD=${LUMA_VNC_PASSWORD}
# Ports
- LUMA_API_PORT=${LUMA_API_PORT:-3000}
- LUMA_VNC_PORT=${LUMA_VNC_PORT:-6080}
- LUMA_DATA_DIR=/data
# LLM Configuration (optional)
- LUMA_LLM_PROVIDER=${LUMA_LLM_PROVIDER:-}
- LUMA_OPENAI_ENDPOINT=${LUMA_OPENAI_ENDPOINT:-}
- LUMA_OPENAI_KEY=${LUMA_OPENAI_KEY:-}
- LUMA_OPENAI_MODEL=${LUMA_OPENAI_MODEL:-}
- LUMA_ANTHROPIC_KEY=${LUMA_ANTHROPIC_KEY:-}
- LUMA_ANTHROPIC_MODEL=${LUMA_ANTHROPIC_MODEL:-}
- LUMA_ANTHROPIC_ENDPOINT=${LUMA_ANTHROPIC_ENDPOINT:-}
ports:
- "${LUMA_API_PORT:-3000}:3000"
- "${LUMA_VNC_PORT:-6080}:6080"
volumes:
- luma-data:/data
shm_size: '2gb'
restart: unless-stopped
volumes:
luma-data:
The container runs five managed processes via supervisord:
| Process | Role |
|---|---|
Xvfb | Virtual framebuffer providing a 1920x1080 display |
fluxbox | Lightweight window manager |
x11vnc | VNC server attached to the virtual display |
websockify | noVNC proxy providing HTTP-based desktop access |
electron | LumaBrowser with REST API, MCP tools, and all extensions |
Startup Sequence
- Entrypoint validates
LUMA_LICENSE_KEYagainst Keygen.sh API - Verifies Enterprise tier with
HEADLESS_DEPLOYentitlement - Activates machine fingerprint (auto-registers if new)
- Pre-seeds license key and LLM config into SQLite database
- Starts all processes via supervisord
- LumaBrowser opens on the virtual display with REST API on port 3000
License Heartbeat
Enterprise floating licenses send a heartbeat ping to Keygen every 5 minutes. On container shutdown, the machine slot is automatically released so it can be reused by another instance.
| Port | Protocol | Service | External |
|---|---|---|---|
3000 | HTTP | REST API + MCP proxy | Yes |
6080 | HTTP | noVNC web desktop | Yes |
5900 | VNC | Internal VNC server | No (localhost only) |
API Endpoints
All LumaBrowser REST API endpoints are available inside the container. Key routes:
| Endpoint | Description |
|---|---|
GET /api/health | Health check with extension list |
GET /api/mcp/tools | List all available MCP tools |
POST /api/mcp/call | Execute any MCP tool |
GET /api/browser/tabs | List open browser tabs |
POST /api/browser/tabs | Create a new tab |
- Non-root user: LumaBrowser runs as the
lumauser inside the container, not root. - VNC password required: The container refuses to start without a
LUMA_VNC_PASSWORD. - Internal VNC port: Port 5900 is only accessible inside the container. External access goes through noVNC on port 6080.
- License key: Passed as a runtime environment variable, never baked into the image.
- Shared memory:
shm_size: 2gbis required. Chromium uses/dev/shmfor rendering; the Docker default of 64MB causes crashes.
Production Recommendations
- Place an HTTPS reverse proxy (nginx, Caddy, Traefik) in front of the noVNC port for encrypted desktop access.
- Use Docker secrets or a
.envfile (gitignored) instead of passing credentials on the command line. - Restrict network access so only trusted clients can reach ports 3000 and 6080.
Container exits immediately
Check docker logs lumabrowser for license validation errors. Common causes:
LUMA_LICENSE_KEYnot set or invalid- License is not Enterprise tier (Pro/Community keys won't work)
- Missing
HEADLESS_DEPLOYentitlement - License has reached its machine limit — deactivate another instance first
- No network access to
api.keygen.sh
noVNC shows a black screen
- Wait 10-15 seconds for LumaBrowser to fully initialize
- Check that
shm_sizeis at least2gbin your compose file - Verify Xvfb is running:
docker exec lumabrowser ps aux | grep Xvfb
REST API not responding
- Verify the container is healthy:
docker psshould show(healthy) - Check LumaBrowser started:
docker logs lumabrowser | grep "HTTP server listening" - Ensure port 3000 is mapped:
docker port lumabrowser
LLM features not working
- Verify LLM env vars are set (
LUMA_LLM_PROVIDER, endpoint, key, model) - For local LLM servers, use
host.docker.internalinstead oflocalhost - Check the LLM server is accessible from inside the container:
docker exec lumabrowser curl http://host.docker.internal:1234/v1/models
D-Bus errors in logs
Messages like Failed to connect to the bus are cosmetic warnings. There is no system bus inside the container, but this does not affect LumaBrowser functionality.