A fully-featured Debian 13 (Trixie) desktop environment running in Docker with web-based remote access via KasmVNC.
Modern AI coding tools — Cursor, Claude Code, Antigravity, OpenCode — have moved beyond code completion into agentic workflows. Through MCP (Model Context Protocol) servers like Playwright MCP, these tools can launch browsers, interact with web pages via accessibility tree snapshots, run terminal commands, and automate entire development workflows — all without vision models, using structured DOM data instead.
This creates a need for a sandboxed desktop environment where AI agents and developers can safely test, debug, and automate:
- Frontend development — AI agents can open a real browser, navigate to
localhost, interact with UI elements through accessibility snapshots, capture screenshots, and debug with DevTools — all inside an isolated container that won't interfere with your host system - VoIP and WebRTC development — test SIP clients, WebRTC peer connections, and media pipelines in a containerized environment with audio support (PulseAudio), network isolation, and real browser-based clients — no host audio stack conflicts
- AI agent workflows — give coding agents like Cursor or Claude Code a full desktop with browser access for end-to-end testing, UI automation, and visual verification, sandboxed from your host machine
- Reproducible test environments — spin up identical, disposable desktops for CI/CD pipelines, QA testing, or live demos, with deterministic plugin configurations via the
PLUGINSenvironment variable
This container provides that sandbox: a complete Debian desktop accessible via any browser, with a plugin system that installs the AI coding tools (Cursor, Claude Code, Antigravity, OpenCode) and development infrastructure (Docker-in-Docker, Homebrew, Chrome) needed for these workflows.
- Debian 13 Trixie base with lightweight init (tini, no systemd)
- XFCE4 desktop environment
- KasmVNC: Web-based VNC with file transfer, audio, and clipboard support
- Homebrew package manager
- Firefox ESR pre-installed
- Plugin system for optional software installation
- Configurable via environment variables
- Passwordless sudo for the desktop user
# Clone the repository
git clone https://github.com/andrius/desktop.git
cd desktop
# Copy and configure environment
cp .env.example .env
# Start the container
docker compose up -d
# Access the desktop at http://localhost:6901Copy .env.example to .env and customize the settings:
cp .env.example .env| Variable | Default | Description |
|---|---|---|
USERNAME |
user |
Desktop username |
USER_PASSWORD |
(empty) | Linux user password (required for XRDP/NoMachine login) |
RESOLUTION |
1920x1080x24 |
Screen resolution |
TZ |
UTC |
Timezone |
VNC_PW |
vncpassword |
VNC password |
VNC_WEB_PORT |
6901 |
KasmVNC web port |
Enable optional software via the PLUGINS environment variable (comma-separated):
PLUGINS=brew,vscode,cursor| Plugin | Description |
|---|---|
brew |
Homebrew package manager |
chrome |
Google Chrome browser (amd64 only) |
xrdp |
XRDP remote desktop (port 3389) |
nomachine |
NoMachine remote desktop (port 4000) |
cursor |
Cursor AI code editor |
vscode |
Visual Studio Code |
claude-code |
Claude Code CLI |
docker |
Docker Engine (DinD) |
antigravity |
Antigravity AI code editor (amd64 only) |
opencode |
OpenCode AI coding agent |
Each plugin is a self-contained directory with init.sh, tests.sh, and README.md. Plugins install on first boot and are skipped on restart.
# List available plugins
/opt/desktop/scripts/plugin-manager.sh list
# Install a specific plugin
/opt/desktop/scripts/plugin-manager.sh vscode
# Test a plugin
/opt/desktop/scripts/plugin-manager.sh test vscode# Test plugins in isolated containers
./scripts/test-plugins.sh brew vscode --verbose
# Test all plugins
./scripts/test-plugins.sh --all --verbose| Service | Port | Protocol | Notes |
|---|---|---|---|
| KasmVNC Web | 6901 | HTTP/WebSocket | Built-in, always available |
| XRDP | 3389 | RDP/TCP | Requires xrdp plugin |
| NoMachine | 4000 | NX/TCP+UDP | Requires nomachine plugin |
XRDP and NoMachine ports are pre-configured in the compose file. Enable the corresponding plugin to activate the service.
# Build the image
make build
# Or using docker compose
docker compose buildPre-built images are available from GitHub Container Registry:
docker pull ghcr.io/andrius/desktop:latestThe repository includes GitHub Actions workflows that automatically build and push images to GitHub Container Registry on:
- Push to main/master branch
- Pull requests
- Weekly schedule (security updates)
- Manual trigger
# Enter the container
docker compose exec desktop bash
# Run system update
/opt/desktop/scripts/maintenance/update-system.sh# Clean temporary files and caches
/opt/desktop/scripts/maintenance/cleanup.sh# Check system health
/opt/desktop/scripts/maintenance/health-check.sh.
├── docker/
│ ├── base/ # Shared base scripts (canonical source)
│ │ └── scripts/ # env-setup.sh, init-user.sh, plugin-manager.sh
│ └── kasmvnc/ # KasmVNC build context
│ ├── Dockerfile
│ ├── scripts/
│ └── configs/
├── plugins/ # Plugin system (each has init.sh, tests.sh, README.md)
│ ├── antigravity/
│ ├── brew/
│ ├── chrome/
│ ├── claude-code/
│ ├── cursor/
│ ├── docker/
│ ├── nomachine/
│ ├── opencode/
│ ├── vscode/
│ └── xrdp/
├── scripts/
│ ├── test-image.sh # Integration test script
│ └── test-plugins.sh # Plugin test runner
├── docs/ # Documentation
├── .github/
│ └── workflows/ # GitHub Actions workflows
├── docker-compose.yml # Docker Compose file
├── .env.example # Environment template
└── README.md
- XFCE4 desktop environment
- Firefox ESR browser
- Xfce4-terminal
- Thunar file manager
- Basic development tools (git, vim, nano, curl, wget)
- Homebrew package manager
- Mesa OpenGL utilities
- PulseAudio (audio support)
- Check if the container is running:
docker ps - Check container logs:
docker compose logs - Verify ports are not in use:
netstat -tlnp | grep 6901
- Increase shared memory: Add
--shm-size=2gor use the compose file - Lower resolution in
.env
- Check internet connectivity inside container
- View plugin manager logs:
cat /var/log/plugin-manager.log - Try manual installation:
/opt/desktop/scripts/plugin-manager.sh <plugin>
- Check X server:
docker compose exec desktop pgrep Xvfb - Verify display variable:
docker compose exec desktop echo $DISPLAY - Restart the container
- Change the default VNC password (
VNC_PW) in production - Set
USER_PASSWORDwhen using XRDP or NoMachine plugins (required for PAM login) - Enable KasmVNC SSL with
KASMVNC_ENABLE_SSL=true, or use HTTPS/TLS termination with a reverse proxy - The container runs with
seccomp:unconfinedfor desktop functionality - Use network isolation in production environments
- Regularly update the container for security patches
MIT License - See LICENSE file for details.
Contributions are welcome! Please open issues or submit pull requests at github.com/andrius/desktop.