Skip to content

Neoplanetz/openclaw-desktop-docker

Repository files navigation

🌐 English | 한국어 | 中文 | 日本語

OpenClaw Docker Desktop Environment

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.

Buy Me A Coffee CTEE

New to Docker? Check out the Beginner's Guide for step-by-step instructions with screenshots.

⚠️ Security notice The default password (claw1234) is published in this README. By default, ports are bound to 127.0.0.1 only (this host) — safe for local use. Before exposing to your LAN or the internet, always change CLAW_PASSWORD in .env and review the port-mapping block in docker-compose.yml.

Architecture

What's Included

Component Details
Base OS Ubuntu 24.04
Architectures linux/amd64, linux/arm64 (multi-arch manifest — Docker picks the right variant automatically)
Desktop XFCE4 with Korean + CJK + emoji fonts
Remote Access TigerVNC + NoVNC (web), xRDP (Remote Desktop), raw VNC
Browser Google Chrome on amd64 / Chromium on arm64 (Google does not ship chrome-stable for arm64; Chromium is CDP-compatible so OpenClaw browser automation behaves identically). Both ship a --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
Agent CLIs claude (Claude Code) and codex (OpenAI Codex) pre-installed via npm. No credentials baked — run claude or codex once to authenticate. Pinnable via build args CLAUDE_CODE_VERSION / CODEX_VERSION.
Desktop Shortcuts OpenClaw Setup, Dashboard, Terminal

Ports

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

Quick Start

Prerequisites

  • Docker Engine 20+

Run from Docker Hub (Recommended)

docker compose up -d

Or standalone (loopback-only — safe default):

docker pull neoplanetz/openclaw-desktop-docker:latest
docker run -d --name openclaw-desktop \
  -p 127.0.0.1:6080:6080 -p 127.0.0.1:5901:5901 \
  -p 127.0.0.1:3389:3389 -p 127.0.0.1:18789:18789 \
  --shm-size=2g --security-opt seccomp=unconfined \
  neoplanetz/openclaw-desktop-docker:latest
# To expose on the LAN, first set -e PASSWORD=<strong>, then drop the
# 127.0.0.1: prefix from the -p flags above.

Build from Source

If you want to build the image yourself:

docker compose up -d --build

Connecting to the Desktop

Web Browser (NoVNC)

Open http://localhost:6080/vnc.html and enter the VNC password (default: claw1234, configurable in .env).

RDP (Remote Desktop)

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.

VNC Client

Connect to localhost:5901 with any VNC viewer.

OpenClaw Setup

How It Works (No Manual Install Needed)

The Docker image ships with Node.js 22, OpenClaw, and a minimal ~/.openclaw/openclaw.json config. On every container start, the entrypoint:

  1. Starts VNC, NoVNC, and xRDP servers
  2. Ensures the OpenClaw config exists (regenerates if missing)
  3. Runs openclaw-sync-display to configure DISPLAY / XAUTHORITY targeting (auto-detects VNC vs xRDP session) and writes OPENCLAW_ALLOW_INSECURE_PRIVATE_WS=1 to ~/.openclaw/.env
  4. Starts the OpenClaw Gateway in the background (openclaw gateway run)
  5. Sets Chrome as the default XFCE web browser
  6. Installs a .bashrc hook that auto-syncs the display when switching between VNC and RDP sessions
  7. Ensures .npmrc with user-writable prefix (/var/openclaw-npm) exists so npm install -g works without root (for clawhub and skill dependencies). The prefix lives outside /home, so installed skills are reset on container recreate — preventing stale openclaw versions from shadowing the image-baked one.

The container ships a systemctl shim that translates OpenClaw's systemd-user calls into direct process management, so openclaw update, openclaw gateway restart, and the dashboard's equivalent flows complete cleanly. The shim is SIGUSR1-first: when the gateway is already running and the on-disk openclaw binary hasn't changed since the daemon started, it sends SIGUSR1 so OpenClaw re-initialises itself in-process (the same mechanism OpenClaw 2026.5+ uses internally for container restarts). This preserves the bound port, Control-UI WebSocket sessions, and per-browser device-pairing approvals — so the dashboard doesn't disconnect on every config write. The full stop + spawn path kicks in only when (a) no gateway is running, or (b) the binary mtime is newer than the running gateway's start time — exactly what openclaw update produces, where a fresh process image is required to load the new code. The gateway unit file is auto-registered on first boot; no manual openclaw gateway install is needed.

Desktop Shortcuts

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. The gateway daemon install at the end completes cleanly via the systemctl shim.
OpenClaw Dashboard Runs openclaw dashboard — opens Chrome with http://127.0.0.1:18789/ and an auto-login token. The setup wizard's "Hatch in Browser" path is rewritten to the same origin by our xdg-open wrapper, so a single device-pairing approve covers every way to open the dashboard.
OpenClaw Terminal Opens an XFCE terminal with the openclaw CLI ready.

First-Time AI Model Setup

Double-click "OpenClaw Setup" on the desktop. The onboarding wizard walks through:

  1. Model / Auth — choose a provider (OpenAI Codex OAuth, Anthropic API key, etc.)
  2. Channels — connect Telegram, Discord, WhatsApp, or skip
  3. Skills — install recommended skills or skip
  4. Gateway daemon — installs cleanly via the systemctl shim

The wizard automatically restarts the Gateway and opens the Dashboard when finished.

Approve the dashboard browser once. OpenClaw 2026.5+ treats every browser/CLI as a separate device with its own pairing identity. The setup wizard's internal client is auto-approved, but the "Hatch in Browser" tab opens as a new device and surfaces "Device pairing required" on first connect. The setup terminal prints the exact command — copy the request id from the dashboard error page and run:

openclaw devices approve <request-id>

The gateway connect failed / using local fallback lines you'll see in the approve output are the intended chicken-and-egg fallback (the CLI itself is a freshly created device, so it can't approve other devices through the gateway yet) — the final Approved … line is success. That browser is permanent from then on. openclaw devices list shows all paired devices.

OpenAI Codex OAuth (ChatGPT Subscription)

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-default

Anthropic API Key

openclaw config set agents.defaults.model.primary anthropic/claude-sonnet-4-6
echo 'ANTHROPIC_API_KEY=sk-ant-...' >> ~/.openclaw/.env

OpenAI API Key

openclaw config set agents.defaults.model.primary openai/gpt-4o
echo 'OPENAI_API_KEY=sk-...' >> ~/.openclaw/.env

Gateway Management

openclaw status                     # Overall status
openclaw gateway status             # Gateway-specific status
openclaw models status              # Model/auth status
openclaw config file                # Print the active config file path
openclaw config get gateway.port    # Get a specific config value (dot path)
openclaw dashboard                  # Open Dashboard with auto-login token

Gateway Authentication

OpenClaw 2026.5.18+ refuses to bind the gateway to a non-loopback interface without auth, and Docker port-forwarding requires that bind. The entrypoint handles this automatically — you do not normally need to touch it:

  • A 256-bit hex token is generated on first boot and persisted to ~/.openclaw/.env (kept across docker compose down/up by the openclaw-home volume).
  • The token is auto-loaded into every login shell via /etc/profile.d/openclaw-gateway-env.sh, so all in-container CLI commands and the systemctl-shim restart path pick it up transparently.
  • The gateway runs with --auth token --bind auto. openclaw status, openclaw devices list, openclaw-update, etc. reuse the same token without any user action.

Accessing the Dashboard from inside the container (recommended) — Use the OpenClaw Dashboard desktop shortcut (NoVNC/RDP) or run openclaw dashboard in a terminal. Either path launches Chrome with the auto-login URL passed as a command-line argument — no clipboard, no token typing.

Accessing the Dashboard from the host browserdocker exec does not have access to the container's X clipboard (the image omits xclip/xsel), so openclaw dashboard --no-open from outside prints the bare URL without the token. Assemble the working URL yourself by appending the token as a fragment:

TOKEN=$(docker exec openclaw-desktop sh -lc \
    'for f in /home/*/.openclaw/.env; do [ -f "$f" ] && grep ^OPENCLAW_GATEWAY_TOKEN= "$f" | cut -d= -f2- && exit; done; exit 1')
echo "http://127.0.0.1:18789/#token=${TOKEN}"

Open the printed URL in the host browser. The #token=… fragment is read by the dashboard JS to authenticate the WebSocket; it is NOT sent in the HTTP request, so it does not appear in access logs.

Overriding the token — Set OPENCLAW_GATEWAY_TOKEN=<value> in .env or docker-compose.yml's environment: block. The entrypoint will honor the pre-set value instead of generating a fresh one (useful with a secrets manager). Custom values must be 32-256 characters using only A-Z, a-z, 0-9, ., _, ~, and -.

Updating OpenClaw

Two tracks, depending on what you want to update:

A. OpenClaw itself (most common). Run inside the container:

openclaw update

This npm install's the latest OpenClaw to /var/openclaw-npm/, then triggers a systemctl --user restart that goes through our shim. Because the on-disk binary is now newer than the running gateway, the shim's mtime check picks the full stop + spawn path and the new code is loaded. No container restart required, no dashboard re-pairing, channel state preserved.

B. Docker image (Node, Chrome, OS packages, shim itself). Run on the host:

docker compose pull          # Fetch the new image from Docker Hub
docker compose down          # Stop the container (named volume preserved)
docker compose up -d         # Recreate against the new image

The openclaw-home volume keeps your workspace, channel settings, paired devices, and auth tokens across recreates. Use docker compose down -v only if you want a fully clean slate (you'll repeat onboarding).

After either path, you can verify the shim chose the expected branch:

cat /tmp/systemctl-shim.log
# Expected lines:
#   restart: SIGUSR1 in-process restart of PID … succeeded     (config-reload-style restarts)
#   restart: binary newer than gateway PID … -- full restart    (right after `openclaw update`)

Configuration

Default openclaw.json

Pre-seeded at ~/.openclaw/openclaw.json:

{
  gateway: {
    mode: "local",
    port: 18789,
    bind: "lan",
    controlUi: {
      allowedOrigins: [
        "http://127.0.0.1:18789",
        "http://localhost:18789",
      ],
    },
    auth: {
      rateLimit: { maxAttempts: 10, windowMs: 60000, lockoutMs: 300000 },
    },
  },
  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 access http://127.0.0.1:18789/
  • controlUi.allowedOrigins — explicit list of browser origins that may open the Dashboard WebSocket. v1.4.19 replaced the older ["*"] wildcard (flagged CRITICAL by openclaw security audit) with the two host-browser URL forms our entrypoint and xdg-open wrapper produce. LAN exposure (uncommented LAN ports in docker-compose.yml): add your host's LAN origin here, e.g. "http://192.168.1.10:18789".
  • auth.rateLimit — token-auth attempt limiter (10 attempts per 60s, 5-minute lockout). The token has 256 bits of entropy so brute force is computationally infeasible, but the audit warns when bind != loopback without rate limiting.
  • browser.enabled: false — CDP browser is disabled by default; set OPENCLAW_BROWSER_ENABLED=true in .env to enable
  • browser.defaultProfile / browser.noSandbox — uses a dedicated openclaw Chrome 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

Custom Username & Password

Edit the .env file in the project root (same directory as docker-compose.yml):

CLAW_USER=myname
CLAW_PASSWORD=mypassword

Then rebuild:

docker compose up -d --build

If changing the username after a previous run, delete the old volume first: docker compose down -v && docker compose up -d --build

Environment Variables

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_GATEWAY_TOKEN OPENCLAW_GATEWAY_TOKEN (auto) Gateway auth token. Required since OpenClaw 2026.5.18+. Entrypoint generates a 256-bit hex token on first boot and persists it to ~/.openclaw/.env; set this to override with a fixed value (e.g. from a secrets manager). See Gateway Authentication.
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

Data Persistence

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
  • 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.

Not persisted: the npm global prefix lives at /var/openclaw-npm (outside the home volume), so packages installed via clawhub or npm install -g are reset on container recreate. This is intentional — it prevents a stale user-installed openclaw from shadowing the image-baked version when you upgrade. Reinstall skills after recreate.

Updating OpenClaw

Standard flow — from a terminal inside the container:

openclaw-update

This single command handles:

  1. Runs openclaw update (npm package upgrade + gateway restart)
  2. Approves the post-restart self scope-upgrade pending via openclaw-pair-latest
  3. Verifies via openclaw gateway status --deep

On OpenClaw 2026.5+, the CLI's own device token sits at operator.pairing scope right after a gateway restart. Any follow-up command needing operator.read (such as gateway status --deep) emits a fresh scope-upgrade pending — but by design no path lets a device auto-approve its own scope upgrade. Without an explicit approve, the gateway stays at Gateway did not become healthy after restart + Capability: pairing-pending.

openclaw-update wraps the follow-up step into one invocation. From v1.4.16 onwards, both the wrapper and the entrypoint first-boot auto-call invoke the helper with --self-scope-upgrade-only, which enforces entry.deviceId == ~/.openclaw/identity/device.json + clientId == "cli" + role == "operator" + scopes ⊆ {operator.pairing, operator.read} inside the helper. External browser/dashboard device pendings are rejected by the filter — the trust boundary is now coded, not just docstring-claimed.

If you ran openclaw update directly (without the wrapper), the manual breakdown is in the scope-upgrade pending approval troubleshooting item.

In-place update vs image rebuild

openclaw-update docker compose build
Speed Fast (in current container) Slow (rebuilds image)
Persistence Current container only — reverts to image-baked version on docker compose down/up Permanent — survives container recreate
When Daily minor updates, quick checks Major / release-cadence upgrades, production deploys

Permanent upgrade:

# OPENCLAW_VERSION=latest in .env / Dockerfile pulls the freshest at build time
docker compose build --no-cache
docker compose down            # omit -v to preserve the user home volume
docker compose up -d

After a rebuild, entrypoint calls the self scope-upgrade approval once during first boot (Pairing : self scope-upgrade approved appears in the boot log), so the container starts healthy with no extra step.

Docker-Specific Workarounds

This setup includes several workarounds for running a full GUI + browser + OpenClaw inside Docker:

Issue Solution
No systemd systemctl shim translates systemd-user calls into direct process management; entrypoint supervises VNC and xRDP startup
Shim restart racing OpenClaw's container-aware in-process restart Shim's restart is SIGUSR1-first: signals the live gateway to re-init itself in-place (matches OpenClaw 2026.5+ container mode). Falls back to stop + spawn only on cold start, or when the on-disk binary mtime is newer than the running gateway's start time (i.e. right after openclaw update, where a new process image is required)
Process-title rename across OpenClaw versions Gateway daemon's process.title is openclaw-gateway on 2026.4.x and openclaw on 2026.5+. Entrypoint, display-sync, and shim accept both titles, then require the process to own the gateway listener so ordinary openclaw CLI commands are not mistaken for the daemon
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 127.0.0.1 — matching what openclaw dashboard already emits. Chrome treats localhost and 127.0.0.1 as distinct security origins with separate localStorage scopes, so unifying every dashboard-open path on the same form is what makes a single device-pairing approve survive subsequent dashboard opens; mixing forms forces double pairing (one per origin). For the same reason every dashboard URL hint we publish — entrypoint startup banner, this README, openclaw.json comment, beginner guide — consistently uses 127.0.0.1:18789
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
openclaw update leaves dashboard showing "update available" systemctl shim's restart handler detects the newer-on-disk binary via mtime and forces a fresh process spawn, so the new code is actually loaded
npm install -g needs root .npmrc sets prefix=/var/openclaw-npm (outside /home) so global installs go to a user-writable directory and stay ephemeral across recreates; PATH exported in .bashrc

Troubleshooting

Container keeps restarting

docker compose logs openclaw-desktop

Check for errors in VNC startup or config validation.

NoVNC shows blank screen

# 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"

RDP shows white screen

docker exec -it openclaw-desktop /etc/init.d/xrdp restart

OpenClaw Gateway not running

# 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"

"Gateway daemon install failed" during onboarding

Earlier versions of this image surfaced a "systemd not available" message because Docker containers have no systemd. The current image ships a shim that handles these calls transparently; you should no longer see this message during onboarding. If you do, check that /usr/bin/systemctl is a symlink to /usr/local/bin/systemctl-shim.

Dashboard shows "control ui requires device identity"

The browser opened with a Docker internal IP instead of 127.0.0.1. Close it and use the "OpenClaw Dashboard" desktop shortcut, which runs openclaw dashboard with the correct URL and token.

Dashboard shows "Device pairing required"

Expected on a new browser's first connect — by design, OpenClaw 2026.5+ requires explicit approval for every browser device (upstream policy: "Operator, browser, Control UI … pairing still require manual approval"). One-time per browser. Single approve is permanent across close/reopen and across the setup-wizard "Hatch in Browser" tab vs the desktop "OpenClaw Dashboard" icon, because both paths land on the same http://127.0.0.1:18789/ origin.

Recommended:

openclaw-pair-latest

This helper reads the gateway's own state file (~/.openclaw/devices/pending.json), picks the latest pending requestId, and runs openclaw devices approve on it — no UUID copy-paste. Handles both first-time pairing and the scope-upgrade pending case with the same command. It's not a daemon and not auto-approval; you invoke it explicitly, same security model as approving by hand.

Manual form (if you prefer to copy the requestId yourself):

openclaw devices approve <request-id-shown-on-the-pairing-screen>

After approve, refresh the dashboard. List paired devices anytime with openclaw devices list. The paired.json file at ~/.openclaw/devices/paired.json should contain exactly one openclaw-control-ui browser entry after a clean setup — if you see two, you're probably running an older image that didn't yet align the xdg-open rewrite target to 127.0.0.1; rebuild from :latest (v1.4.14+) and the duplicate disappears.

Note: pairing requestIds expire after ~5 minutes. If approve fails with unknown requestId, refresh the dashboard once to get a fresh id, then run openclaw-pair-latest again. The first run of openclaw devices approve on a fresh container may print gateway connect failed / using local fallback — that's the intended chicken-and-egg fallback (the CLI is itself a fresh device); the final Approved … line is success.

Why no auto-approve daemon? We deliberately don't ship one. OpenClaw's upstream policy is explicit about manual approval for operator/Control UI devices, and a default-on auto-approver would weaken security for anyone enabling LAN exposure (commented block in docker-compose.yml). The openclaw-pair-latest helper keeps the manual-approve trust boundary intact and just removes the typing friction.

openclaw gateway status --deep shows "scope upgrade pending approval"

OpenClaw 2026.5+ auto-creates a CLI device on the first gateway connect, but seeds it with operator.pairing scope only. Any later command that needs operator.read (e.g. openclaw gateway status --deep, openclaw devices list) emits a fresh scope-upgrade request — and by design there is no path for a device to auto-approve its own upgrade. The result: each probe surfaces a new requestId, ~/.openclaw/devices/pending.json accumulates entries, and the health probe stays failed.

Symptom:

Connectivity probe: failed
  scope upgrade pending approval (requestId: <uuid>)
Capability: pairing-pending

This state shows up especially often right after openclaw update — the previous device tokens look under-privileged under the new core's permission model, and the update's Restarting service... step ends with Gateway did not become healthy after restart. Same root cause.

Fix:

openclaw-pair-latest

The helper extracts the freshest requestId from pending.json and approves it. On the first call you'll see the intended local fallback sequence that breaks the chicken-and-egg:

gateway connect failed: ... scope upgrade pending approval (requestId: <new>)
Direct scope access failed; using local fallback.
Approved <deviceId> (<requestId>)

Verify:

openclaw gateway status --deep | grep -E "Connectivity|Capability"
# Connectivity probe: ok
# Capability: read-only      (or ready/granted — no longer pairing-pending)

If the first call doesn't clear it (transient state), run openclaw-pair-latest once more. Stale requestIds older than ~5 minutes expire and are rejected as unknown requestId, so surface a fresh one with openclaw gateway status --deep immediately before re-running the helper.

File Structure

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

About

Docker-powered Ubuntu desktop with OpenClaw pre-installed — access via browser (NoVNC), RDP, or VNC. AI agent gateway ready out of the box.

Topics

Resources

Stars

Watchers

Forks

Packages

 
 
 

Contributors