Run the OpenCode Desktop application inside a browser-accessible Linux desktop container, built on LinuxServer.io's KasmVNC base image.
This provides a full desktop environment streamed to your browser, allowing you to use the OpenCode Desktop app (and CLI) from any device on your network without needing a dedicated VM.
- Browser-based desktop - Access OpenCode Desktop via any modern web browser at
http://docker-host:3000 - Persistent storage - All OpenCode settings, authentication, plugins, and cache survive container restarts
- Project workspace - Map a host directory to
/workspaceand organise projects in subfolders - LinuxServer conventions - Uses
PUID/PGID,TZ,/configvolume, and s6-overlay for easy maintenance - Optional GPU acceleration - Pass through Intel/AMD iGPU for smoother desktop rendering
- Optional Docker access - Mount host Docker socket to let OpenCode run Docker commands
- Runtime package installation - Install additional dev tools on startup via the
EXTRA_PACKAGESenvironment variable
- A Linux Docker host with Docker Engine and Docker Compose (v2) installed
- (Optional) Intel or AMD integrated GPU for DRI3 acceleration
- (Optional) A reverse proxy if you want external/SSL access
- (Optional) Unraid server with Community Applications plugin
-
Clone or copy this repository to your Docker host.
-
Create the data and projects directories on your host:
mkdir -p opencode-data opencode-projects
-
Build and start the container:
docker compose up -d --build
-
Open your browser and navigate to:
http://<docker-host-ip>:3000If you set a
PASSWORD, you will be prompted for it. You will then see the Ubuntu desktop with OpenCode Desktop already running. -
Create project folders inside
/workspace(e.g.,/workspace/my-project) and initialise OpenCode inside each one:cd /workspace/my-project opencode-cli /init
An official Unraid template is included for easy deployment via the Community Applications plugin.
- Template file:
unraid/opencode-desktop.xml - Full guide: See
UNRAID.mdfor step-by-step instructions, screenshots, and troubleshooting.
Quick steps for Unraid users:
- Go to Docker > Add Container in Unraid.
- Set Template URL to:
https://raw.githubusercontent.com/djurcola/opencode-docker/main/unraid/opencode-desktop.xml - Click Load Template, adjust paths and ports, then Apply.
| Variable | Required | Default | Description |
|---|---|---|---|
PUID |
No | 1000 |
User ID to run as inside the container |
PGID |
No | 1000 |
Group ID to run as inside the container |
TZ |
No | Etc/UTC |
Timezone (e.g. Europe/London) |
PASSWORD |
No | (none) | Password for the KasmVNC web UI |
EXTRA_PACKAGES |
No | (none) | Space-separated list of APT packages to install at container startup |
Tip: You can copy
.env.exampleto.env, edit the values, and addenv_file: - .envto yourdocker-compose.ymlif you prefer.
| Argument | Default | Description |
|---|---|---|
OPENCODE_VERSION |
v1.14.28 |
OpenCode Desktop GitHub release tag to install |
TARGETARCH |
amd64 |
Target architecture (amd64 or arm64) |
To update OpenCode Desktop, change OPENCODE_VERSION in docker-compose.yml and run:
docker compose up -d --build| Host Path | Container Path | Purpose |
|---|---|---|
./opencode-data |
/config |
Persistent OpenCode config, auth, cache, plugins, themes, and desktop settings |
./opencode-projects |
/workspace |
Your code projects |
/var/run/docker.sock |
/var/run/docker.sock |
(Optional) Host Docker socket for OpenCode Docker tools |
| Host | Container | Purpose |
|---|---|---|
3000 |
3000 |
KasmVNC web interface |
You can install additional packages without rebuilding the image by using the EXTRA_PACKAGES environment variable.
environment:
- EXTRA_PACKAGES="golang-go ruby rustc cargo postgresql-client redis-tools"docker exec -it opencode-desktop bash
apt-get update && apt-get install -y <package-name>Note: Packages installed via
EXTRA_PACKAGESare re-installed every time the container starts. Packages installed manually inside the running container will be lost when the container is recreated.
This repository includes a GitHub Actions workflow (.github/workflows/build.yml) that can automatically build and push multi-architecture Docker images to the GitHub Container Registry (ghcr.io).
- Checks for new OpenCode releases every day at 06:00 UTC
- Compares the latest release with the version pinned in
Dockerfile - Auto-updates
Dockerfileand commits the change when a new version is found - Builds multi-arch images for
linux/amd64andlinux/arm64 - Pushes tagged images:
ghcr.io/YOUR_USERNAME/opencode-desktop-docker:latestghcr.io/YOUR_USERNAME/opencode-desktop-docker:v1.x.xghcr.io/YOUR_USERNAME/opencode-desktop-docker:amd64-v1.x.xghcr.io/YOUR_USERNAME/opencode-desktop-docker:arm64-v1.x.x
- Push this repository to GitHub.
- Go to Settings > Actions > General and ensure Workflow permissions includes Read and write permissions (needed to push packages).
- The workflow will run automatically on schedule. You can also trigger it manually from the Actions tab.
Instead of building locally, you can use the published image:
services:
opencode-desktop:
image: ghcr.io/YOUR_USERNAME/opencode-desktop-docker:latest
# Remove or comment out the 'build:' blockImportant: Replace
YOUR_USERNAMEwith your actual GitHub username or organisation name.
You can manually trigger a build with a specific version from the GitHub Actions tab using workflow_dispatch. This is useful if you want to build an older version or force a rebuild.
If you have set up the GitHub Actions workflow, simply pull the latest image:
docker compose pull
docker compose up -d- Check the OpenCode releases page for the latest version.
- Update the
OPENCODE_VERSIONbuild argument indocker-compose.yml. - Rebuild and restart:
docker compose up -d --build
LinuxServer regularly updates their base images. To pull the latest base image and rebuild:
docker compose pull
docker compose up -d --buildConsider running Diun (Docker Image Update Notifier) to get notified when new images are available on ghcr.io.
You can place a reverse proxy in front of KasmVNC. The container exposes plain HTTP on port 3000.
server {
listen 443 ssl;
server_name opencode.yourdomain.com;
location / {
proxy_pass http://opencode-desktop:3000;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
}
}- WebSockets: KasmVNC requires WebSocket support. Ensure your proxy forwards the
UpgradeandConnectionheaders. - Path-based proxying: KasmVNC does not natively support subpaths (e.g.
/opencode/). Use a subdomain instead. - Authentication: KasmVNC provides basic HTTP auth via the
PASSWORDvariable. For stronger security, offload authentication to your reverse proxy or Authelia/Authentik.
To enable DRI3 GPU acceleration for smoother desktop performance, pass your Intel or AMD render device into the container:
devices:
- /dev/dri:/dev/driNVIDIA: KasmVNC DRI3 does not support the proprietary NVIDIA driver. It works with Intel (
i965,i915) and AMD (amdgpu,radeon) open-source drivers only.
If your host does not have a compatible GPU (or you choose not to pass one through), KasmVNC and WebKitGTK will fall back to software rendering, which can consume a lot of CPU. You can enable automatic low-resource optimisations:
- Remove or comment out the
/dev/dridevice mapping indocker-compose.yml. - Uncomment the following environment variables in
docker-compose.yml:environment: - DISABLE_DRI=true - WEBKIT_DISABLE_COMPOSITING_MODE=1
When DISABLE_DRI=true is set, the container automatically writes a CPU-optimised kasmvnc.yaml that:
- Caps the screen-capture frame rate to 24 fps (matching official Kasm defaults)
- Lowers JPEG quality to 4–7 (more compression = less CPU)
- Requires >60% of the screen to change for 10 seconds before entering “video mode”
- Prevents the browser client from overriding these server settings
WEBKIT_DISABLE_COMPOSITING_MODE=1 stops OpenCode Desktop’s WebKitGTK engine from wasting CPU cycles trying to GPU-composite web content inside a software-only container.
Trade-offs: The desktop will feel slightly less “smooth” than a GPU-accelerated session. For writing code in OpenCode, the difference is usually negligible.
Because the container uses LinuxServer's /config convention, all OpenCode data lives inside the mounted ./opencode-data directory on your host.
| Inside container | On host (if mapped to ./opencode-data) |
Contents |
|---|---|---|
/config/.config/opencode/ |
./opencode-data/.config/opencode/ |
Global config (opencode.json, tui.json), plugins, agents, commands, themes |
/config/.local/share/opencode/ |
./opencode-data/.local/share/opencode/ |
Auth tokens, logs, sessions |
/config/.cache/opencode/ |
./opencode-data/.cache/opencode/ |
Provider package cache, node_modules for npm plugins |
/workspace/ |
./opencode-projects/ |
Your code projects |
Project-level OpenCode files (e.g. .opencode/plugins/, AGENTS.md) should be committed to your individual project repositories inside /workspace.
By default, the docker-compose.yml mounts the host Docker socket (/var/run/docker.sock) as read-only. This allows OpenCode to run Docker commands on the host Docker daemon. This is the recommended approach.
If you need true Docker-in-Docker isolation, you can run the container with --privileged and mount a dedicated volume for /var/lib/docker. See the LinuxServer KasmVNC documentation for details.
Check the container logs:
docker logs -f opencode-desktopIf you see sandbox-related errors, the --no-sandbox flag is already applied in the autostart script. You can also try running OpenCode manually inside the container:
docker exec -it opencode-desktop bash
/usr/bin/OpenCode --no-sandboxEnsure the directories on your host are owned by the same user you specify with PUID/PGID:
sudo chown -R 1000:1000 ./opencode-data ./opencode-projectsThis usually means OpenCode Desktop crashed or the autostart script failed. Check the logs and ensure all Electron dependencies are present. Rebuilding the image with --no-cache can help:
docker compose build --no-cache
docker compose up -dPlugins installed via npm are cached in /config/.cache/opencode/node_modules/. If this directory is not inside your persistent volume, they will be lost on restart. Ensure your ./opencode-data volume is correctly mapped.
This wrapper is provided as-is for personal use. OpenCode itself is licensed under the MIT License.