A turnkey Docker setup for running OpenClaw inside a full Ubuntu 24.04 GUI desktop, accessible via web browser (NoVNC), RDP, or VNC.
Everything is pre-installed — Node.js 22, OpenClaw, Google Chrome, and a default Gateway config. On first boot the Gateway starts automatically; just set your AI model and go.
New to Docker? Check out the Beginner's Guide for step-by-step instructions with screenshots.
| Component | Details |
|---|---|
| Base OS | Ubuntu 24.04 |
| Desktop | XFCE4 with Korean + CJK + emoji fonts |
| Remote Access | TigerVNC + NoVNC (web), xRDP (Remote Desktop), raw VNC |
| Browser | Google Chrome (default, --no-sandbox wrapper) |
| Runtime | Node.js 22 (NodeSource) |
| OpenClaw | Latest from npm, default config pre-seeded, Gateway auto-starts, user-local npm prefix for skill installs |
| Desktop Shortcuts | OpenClaw Setup, Dashboard, Terminal |
| Port | Service |
|---|---|
6080 |
NoVNC — access the desktop via web browser |
5901 |
VNC — direct VNC client connection |
3389 |
RDP — Windows Remote Desktop / Remmina |
18789 |
OpenClaw Gateway & Dashboard |
- Docker Engine 20+
docker compose up -dOr standalone:
docker pull neoplanetz/openclaw-desktop-docker:latest
docker run -d --name openclaw-desktop \
-p 6080:6080 -p 5901:5901 -p 3389:3389 -p 18789:18789 \
--shm-size=2g --security-opt seccomp=unconfined \
neoplanetz/openclaw-desktop-docker:latestIf you want to build the image yourself:
docker compose up -d --buildOpen http://localhost:6080/vnc.html and enter the VNC password (default: claw1234, configurable in .env).
Connect to localhost:3389 with any RDP client:
- Windows:
mstsc - macOS: Microsoft Remote Desktop
- Linux: Remmina
Login with your configured username and password (default: claw / claw1234, configurable in .env). Leave Domain blank.
Connect to localhost:5901 with any VNC viewer.
The Docker image ships with Node.js 22, OpenClaw, and a minimal ~/.openclaw/openclaw.json config. On every container start, the entrypoint:
- Starts VNC, NoVNC, and xRDP servers
- Ensures the OpenClaw config exists (regenerates if missing)
- Runs
openclaw-sync-displayto configure DISPLAY / XAUTHORITY targeting (auto-detects VNC vs xRDP session) and writesOPENCLAW_ALLOW_INSECURE_PRIVATE_WS=1to~/.openclaw/.env - Starts the OpenClaw Gateway in the background (
openclaw gateway run) - Sets Chrome as the default XFCE web browser
- Installs a
.bashrchook that auto-syncs the display when switching between VNC and RDP sessions - Ensures
.npmrcwith user-local prefix (~/.npm-global) exists sonpm install -gworks without root (for clawhub and skill dependencies)
Since Docker has no systemd, the Gateway daemon install step during onboarding will fail — this is expected and can be safely ignored. The entrypoint manages the Gateway process directly.
Three icons are placed on the XFCE desktop:
| Icon | What It Does |
|---|---|
| OpenClaw Setup | Runs openclaw onboard — configure AI model/auth, channels (Telegram, Discord, etc.), and skills. Gateway daemon install failure at the end is normal. |
| OpenClaw Dashboard | Runs openclaw dashboard — opens Chrome with the correct localhost URL and auto-login token. |
| OpenClaw Terminal | Opens an XFCE terminal with the openclaw CLI ready. |
Double-click "OpenClaw Setup" on the desktop. The onboarding wizard walks through:
- Model / Auth — choose a provider (OpenAI Codex OAuth, Anthropic API key, etc.)
- Channels — connect Telegram, Discord, WhatsApp, or skip
- Skills — install recommended skills or skip
- Gateway daemon — will fail (no systemd) — ignore this
The wizard automatically restarts the Gateway and opens the Dashboard when finished.
If you have a ChatGPT Plus/Pro subscription, select "OpenAI Codex (ChatGPT OAuth)" during onboarding. A browser window opens for you to log into your OpenAI account. After authorization, the model is set automatically.
Or run directly in the terminal:
openclaw models auth login --provider openai-codex --set-defaultopenclaw config set agents.defaults.model.primary anthropic/claude-sonnet-4-6
echo 'ANTHROPIC_API_KEY=sk-ant-...' >> ~/.openclaw/.envopenclaw config set agents.defaults.model.primary openai/gpt-4o
echo 'OPENAI_API_KEY=sk-...' >> ~/.openclaw/.envopenclaw status # Overall status
openclaw gateway status # Gateway-specific status
openclaw models status # Model/auth status
openclaw config get # View current config
openclaw dashboard # Open Dashboard with auto-login tokenPre-seeded at ~/.openclaw/openclaw.json:
{
gateway: {
mode: "local",
port: 18789,
bind: "lan",
controlUi: {
allowedOrigins: ["*"],
},
},
browser: {
enabled: false,
defaultProfile: "openclaw",
noSandbox: true,
},
plugins: {
entries: {
browser: {
enabled: true,
},
},
},
agents: {
defaults: {
workspace: "~/.openclaw/workspace",
},
},
env: {
vars: {
TZ: "Asia/Seoul",
},
},
}bind: "lan"— listens on all interfaces so the host can accesshttp://localhost:18789/controlUi.allowedOrigins: ["*"]— allows Dashboard access from any origin (needed inside Docker)browser.enabled: false— CDP browser is disabled by default; setOPENCLAW_BROWSER_ENABLED=truein.envto enablebrowser.defaultProfile/browser.noSandbox— uses a dedicatedopenclawChrome profile and disables the sandbox (required in Docker)plugins.entries.browser.enabled: true— browser plugin is registered so agents can use browser tools when the browser is enabled- No AI model is configured by default — set one via onboarding or CLI
Edit the .env file in the project root (same directory as docker-compose.yml):
CLAW_USER=myname
CLAW_PASSWORD=mypasswordThen rebuild:
docker compose up -d --buildIf changing the username after a previous run, delete the old volume first:
docker compose down -v && docker compose up -d --build
These are set automatically from .env via docker-compose.yml:
.env Variable |
Container Env | Default | Description |
|---|---|---|---|
CLAW_USER |
USER |
claw |
Linux username |
CLAW_PASSWORD |
PASSWORD |
claw1234 |
VNC / RDP / sudo password |
OPENCLAW_VERSION |
(build arg) | latest |
OpenClaw npm package version (e.g. latest, 2026.3.28) — used at docker compose build time |
| — | VNC_RESOLUTION |
1920x1080 |
Desktop resolution |
| — | VNC_COL_DEPTH |
24 |
Color depth |
| — | TZ |
Asia/Seoul |
Timezone |
| — | OPENCLAW_ALLOW_INSECURE_PRIVATE_WS |
1 |
Allows plaintext ws:// to Docker-internal private IPs (details) |
OPENCLAW_BROWSER_ENABLED |
OPENCLAW_BROWSER_ENABLED |
false |
Enable OpenClaw CDP browser (Chrome profile: openclaw, --no-sandbox) |
OPENCLAW_DISPLAY_TARGET |
OPENCLAW_DISPLAY_TARGET |
auto |
Display targeting policy: auto, vnc, rdp |
| — | OPENCLAW_X_DISPLAY |
— | Hard override for DISPLAY (e.g. :1, :10) |
| — | OPENCLAW_X_AUTHORITY |
— | Hard override for XAUTHORITY path |
The openclaw-home named volume mounts to the configured user's home directory (/home/claw by default). This preserves:
- OpenClaw config, credentials, and conversation history
- Globally installed npm packages (
~/.npm-global/) including clawhub and skills - Chrome profile and bookmarks
- Desktop customizations
- SSH keys, shell history, etc.
Data survives docker compose down / up. Only docker volume rm openclaw-home destroys it.
This setup includes several workarounds for running a full GUI + browser + OpenClaw inside Docker:
| Issue | Solution |
|---|---|
| No systemd | Entrypoint manages VNC, xRDP, and Gateway processes directly |
| Chrome needs sandbox | Wrapper script adds --no-sandbox to every launch |
xdg-open uses Docker internal IP |
Wrapper rewrites 172.x.x.x / 10.x.x.x URLs to localhost |
| Browser detaches from terminal | setsid in xdg-open wrapper prevents SIGHUP on terminal close |
| Chrome profile lock conflicts | Stale SingletonLock files cleaned once at container start |
| XFCE default browser | Custom exo-helper + mimeapps.list set on every start |
VNC password (vncpasswd missing) |
3-tier fallback: vncpasswd binary → openssl → pure Python DES |
| Firefox snap broken in Docker | Replaced with Google Chrome deb package |
Gateway health check blocks ws:// to non-loopback |
OPENCLAW_ALLOW_INSECURE_PRIVATE_WS=1 permits plaintext ws:// to RFC 1918 private IPs (Docker internal network only, added in v2026.2.19) |
| VNC↔RDP display mismatch | openclaw-sync-display helper auto-detects active session (VNC :1 vs xRDP :10+), restarts gateway with correct DISPLAY; .bashrc hook catches transitions |
npm install -g needs root |
.npmrc sets prefix=~/.npm-global so global installs go to user-writable directory; PATH exported in .bashrc |
docker compose logs openclaw-desktopCheck for errors in VNC startup or config validation.
# Replace 'claw' with your CLAW_USER if changed in .env
docker exec -it openclaw-desktop bash
su - claw -c "vncserver -kill :1"
su - claw -c "vncserver :1 -geometry 1920x1080 -depth 24 -localhost no"docker exec -it openclaw-desktop /etc/init.d/xrdp restart# Replace 'claw' with your CLAW_USER if changed in .env
docker exec -u claw openclaw-desktop openclaw status
# Manual restart:
docker exec -u claw openclaw-desktop bash -c \
"nohup openclaw gateway run >> ~/.openclaw/gateway.log 2>&1 & disown"This is expected — Docker containers have no systemd. The entrypoint handles Gateway lifecycle instead. Ignore this message.
The browser opened with a Docker internal IP instead of localhost. Close it and use the "OpenClaw Dashboard" desktop shortcut, which runs openclaw dashboard with the correct URL and token.
openclaw-desktop-docker/
├── .env # User configuration (CLAW_USER, CLAW_PASSWORD)
├── Dockerfile # Ubuntu 24.04 base image
├── docker-compose.yml # Compose configuration
├── entrypoint.sh # Runtime: VNC, xRDP, Chrome config, Gateway
├── README.md # Documentation (EN, KO, ZH, JA)
├── assets/ # Images & architecture diagrams
│ ├── architecture_*.svg
│ ├── dockerized_openclaw.png
│ └── openclaw_desktop_web.png
├── configs/ # Config templates (copied at build/runtime)
│ ├── vnc/xstartup # VNC session startup
│ ├── xrdp/startwm.sh # xRDP session startup
│ ├── xrdp/reconnectwm.sh # xRDP reconnection hook
│ └── ...
├── scripts/ # Helper scripts
│ └── openclaw-sync-display # Policy-based X11 display targeting
└── docs/ # Guides & changelog
├── CHANGELOG.md
├── DOCKERHUB_OVERVIEW.md
├── GUIDE_FOR_BEGINNERS.*.md
└── images/ # Guide screenshots

