From ef69c4431a1708e3300d5d739cbfa8f73c49896d Mon Sep 17 00:00:00 2001 From: f-trycua Date: Thu, 9 Oct 2025 23:41:51 -0700 Subject: [PATCH 01/10] Add vanilla Docker XFCE container for CUA MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Create a lightweight alternative to Kasm-based container with minimal dependencies. Features vanilla Ubuntu 22.04 with XFCE, TigerVNC, noVNC, and computer-server pre-installed. Key features: - Vanilla XFCE desktop environment - TigerVNC server (port 5901) - noVNC web interface (port 6901) - computer-server WebSocket API (port 8000) - Python 3.11 with automation tools - Firefox with telemetry disabled - Supervisord for process management - Persistent storage support Benefits over Kasm: - Reduced dependencies (no KasmWeb infrastructure) - Smaller image size - Full control over all components - Easy customization - Independent maintenance Includes: - Comprehensive README and quickstart guide - Makefile for common operations - docker-compose.yml for orchestration - Example Python scripts - Startup scripts for all services 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude --- libs/docker-xfce/.dockerignore | 5 + libs/docker-xfce/.gitignore | 4 + libs/docker-xfce/Dockerfile | 122 +++++++++ libs/docker-xfce/LICENSE | 21 ++ libs/docker-xfce/Makefile | 127 ++++++++++ libs/docker-xfce/QUICKSTART.md | 166 ++++++++++++ libs/docker-xfce/README.md | 238 ++++++++++++++++++ libs/docker-xfce/docker-compose.yml | 44 ++++ libs/docker-xfce/example.py | 213 ++++++++++++++++ .../src/scripts/start-computer-server.sh | 13 + libs/docker-xfce/src/scripts/start-novnc.sh | 15 ++ libs/docker-xfce/src/scripts/start-vnc.sh | 22 ++ libs/docker-xfce/src/scripts/xstartup.sh | 21 ++ .../src/supervisor/supervisord.conf | 30 +++ 14 files changed, 1041 insertions(+) create mode 100644 libs/docker-xfce/.dockerignore create mode 100644 libs/docker-xfce/.gitignore create mode 100644 libs/docker-xfce/Dockerfile create mode 100644 libs/docker-xfce/LICENSE create mode 100644 libs/docker-xfce/Makefile create mode 100644 libs/docker-xfce/QUICKSTART.md create mode 100644 libs/docker-xfce/README.md create mode 100644 libs/docker-xfce/docker-compose.yml create mode 100644 libs/docker-xfce/example.py create mode 100644 libs/docker-xfce/src/scripts/start-computer-server.sh create mode 100644 libs/docker-xfce/src/scripts/start-novnc.sh create mode 100644 libs/docker-xfce/src/scripts/start-vnc.sh create mode 100644 libs/docker-xfce/src/scripts/xstartup.sh create mode 100644 libs/docker-xfce/src/supervisor/supervisord.conf diff --git a/libs/docker-xfce/.dockerignore b/libs/docker-xfce/.dockerignore new file mode 100644 index 00000000..d4352f88 --- /dev/null +++ b/libs/docker-xfce/.dockerignore @@ -0,0 +1,5 @@ +README.md +.git +.gitignore +*.md +LICENSE diff --git a/libs/docker-xfce/.gitignore b/libs/docker-xfce/.gitignore new file mode 100644 index 00000000..0a2449a1 --- /dev/null +++ b/libs/docker-xfce/.gitignore @@ -0,0 +1,4 @@ +storage/ +shared/ +*.log +.DS_Store diff --git a/libs/docker-xfce/Dockerfile b/libs/docker-xfce/Dockerfile new file mode 100644 index 00000000..94326ae2 --- /dev/null +++ b/libs/docker-xfce/Dockerfile @@ -0,0 +1,122 @@ +# CUA Docker XFCE Container +# Vanilla XFCE desktop with noVNC and computer-server + +FROM ubuntu:22.04 + +# Avoid prompts from apt +ENV DEBIAN_FRONTEND=noninteractive + +# Set environment variables +ENV HOME=/home/cua +ENV DISPLAY=:1 +ENV VNC_PORT=5901 +ENV NOVNC_PORT=6901 +ENV API_PORT=8000 +ENV VNC_RESOLUTION=1920x1080 +ENV VNC_COL_DEPTH=24 + +# Create user +RUN useradd -m -s /bin/bash -G sudo cua && \ + echo "cua:password" | chpasswd && \ + echo "cua ALL=(ALL) NOPASSWD:ALL" >> /etc/sudoers + +# Install system dependencies +RUN apt-get update && apt-get install -y \ + # Desktop environment + xfce4 \ + xfce4-terminal \ + xfce4-goodies \ + dbus-x11 \ + # VNC server + tigervnc-standalone-server \ + tigervnc-common \ + # noVNC dependencies + python3 \ + python3-pip \ + python3-numpy \ + git \ + net-tools \ + supervisor \ + # Computer-server dependencies + python3.11 \ + python3-tk \ + python3-dev \ + gnome-screenshot \ + wmctrl \ + ffmpeg \ + socat \ + xclip \ + # Browser + wget \ + software-properties-common \ + # Build tools + build-essential \ + libncursesw5-dev \ + libssl-dev \ + libsqlite3-dev \ + tk-dev \ + libgdbm-dev \ + libc6-dev \ + libbz2-dev \ + libffi-dev \ + zlib1g-dev \ + && rm -rf /var/lib/apt/lists/* + +# Install Python 3.11 +RUN add-apt-repository ppa:deadsnakes/ppa && \ + apt-get update && \ + apt-get install -y python3.11 python3.11-distutils && \ + rm -rf /var/lib/apt/lists/* + +# Install noVNC +RUN git clone https://github.com/novnc/noVNC.git /opt/noVNC && \ + git clone https://github.com/novnc/websockify /opt/noVNC/utils/websockify && \ + ln -s /opt/noVNC/vnc.html /opt/noVNC/index.html + +# Install computer-server +RUN pip3 install cua-computer-server + +# Install Firefox +RUN add-apt-repository -y ppa:mozillateam/ppa && \ + echo 'Package: *\nPin: release o=LP-PPA-mozillateam\nPin-Priority: 1001' > /etc/apt/preferences.d/mozilla-firefox && \ + apt-get update && \ + apt-get install -y firefox && \ + rm -rf /var/lib/apt/lists/* + +# Configure Firefox defaults +RUN mkdir -p /etc/firefox/syspref.js && \ + echo 'pref("datareporting.policy.firstRunURL", "");' >> /etc/firefox/syspref.js && \ + echo 'pref("datareporting.policy.dataSubmissionEnabled", false);' >> /etc/firefox/syspref.js && \ + echo 'pref("datareporting.healthreport.service.enabled", false);' >> /etc/firefox/syspref.js && \ + echo 'pref("datareporting.healthreport.uploadEnabled", false);' >> /etc/firefox/syspref.js && \ + echo 'pref("browser.aboutwelcome.enabled", false);' >> /etc/firefox/syspref.js + +# Copy startup scripts +COPY src/supervisor/ /etc/supervisor/conf.d/ +COPY src/scripts/ /usr/local/bin/ + +# Make scripts executable +RUN chmod +x /usr/local/bin/*.sh + +# Setup VNC +USER cua +WORKDIR /home/cua + +# Create VNC password file +RUN mkdir -p $HOME/.vnc && \ + echo "password" | vncpasswd -f > $HOME/.vnc/passwd && \ + chmod 600 $HOME/.vnc/passwd + +# Configure XFCE for first start +RUN mkdir -p $HOME/.config/xfce4/xfconf/xfce-perchannel-xml + +# Create storage and shared directories +RUN mkdir -p $HOME/storage $HOME/shared + +USER root + +# Expose ports +EXPOSE $VNC_PORT $NOVNC_PORT $API_PORT + +# Start services via supervisor +CMD ["/usr/bin/supervisord", "-c", "/etc/supervisor/supervisord.conf"] diff --git a/libs/docker-xfce/LICENSE b/libs/docker-xfce/LICENSE new file mode 100644 index 00000000..6899a9db --- /dev/null +++ b/libs/docker-xfce/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2025 CUA + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/libs/docker-xfce/Makefile b/libs/docker-xfce/Makefile new file mode 100644 index 00000000..e3aa2879 --- /dev/null +++ b/libs/docker-xfce/Makefile @@ -0,0 +1,127 @@ +.PHONY: build run stop push clean test logs shell + +IMAGE_NAME := trycua/cua-docker-xfce +TAG := latest +CONTAINER_NAME := cua-docker-xfce-test + +# Build the Docker image +build: + docker build -t $(IMAGE_NAME):$(TAG) . + +# Run the container +run: + docker run -d \ + --name $(CONTAINER_NAME) \ + --shm-size=512m \ + -p 5901:5901 \ + -p 6901:6901 \ + -p 8000:8000 \ + $(IMAGE_NAME):$(TAG) + @echo "Container started!" + @echo "noVNC: http://localhost:6901" + @echo "VNC: localhost:5901 (password: password)" + @echo "API: http://localhost:8000" + +# Run with custom resolution +run-hd: + docker run -d \ + --name $(CONTAINER_NAME) \ + --shm-size=512m \ + -p 5901:5901 \ + -p 6901:6901 \ + -p 8000:8000 \ + -e VNC_RESOLUTION=1280x720 \ + $(IMAGE_NAME):$(TAG) + +# Run with persistent storage +run-persist: + mkdir -p ./storage ./shared + docker run -d \ + --name $(CONTAINER_NAME) \ + --shm-size=512m \ + -p 5901:5901 \ + -p 6901:6901 \ + -p 8000:8000 \ + -v $(PWD)/storage:/home/cua/storage \ + -v $(PWD)/shared:/home/cua/shared \ + $(IMAGE_NAME):$(TAG) + +# Stop and remove the container +stop: + docker stop $(CONTAINER_NAME) || true + docker rm $(CONTAINER_NAME) || true + +# Push to Docker Hub +push: + docker push $(IMAGE_NAME):$(TAG) + +# Clean up everything +clean: stop + docker rmi $(IMAGE_NAME):$(TAG) || true + rm -rf ./storage ./shared + +# Run tests +test: build run + @echo "Waiting for services to start..." + @sleep 10 + @echo "Testing noVNC..." + @curl -f http://localhost:6901 > /dev/null && echo "✓ noVNC is running" || echo "✗ noVNC failed" + @echo "Testing API..." + @curl -f http://localhost:8000 > /dev/null && echo "✓ API is running" || echo "✗ API failed" + @$(MAKE) stop + +# View logs +logs: + docker logs -f $(CONTAINER_NAME) + +# View supervisor logs +logs-supervisor: + docker exec $(CONTAINER_NAME) tail -f /var/log/supervisor/supervisord.log + +# View individual service logs +logs-vnc: + docker exec $(CONTAINER_NAME) tail -f /var/log/supervisor/vncserver.log + +logs-novnc: + docker exec $(CONTAINER_NAME) tail -f /var/log/supervisor/novnc.log + +logs-api: + docker exec $(CONTAINER_NAME) tail -f /var/log/supervisor/computer-server.log + +# Open a shell in the container +shell: + docker exec -it $(CONTAINER_NAME) /bin/bash + +# Check supervisor status +status: + docker exec $(CONTAINER_NAME) supervisorctl status + +# Restart services +restart-services: + docker exec $(CONTAINER_NAME) supervisorctl restart all + +# Create a snapshot +snapshot: + docker commit $(CONTAINER_NAME) $(IMAGE_NAME):snapshot + @echo "Snapshot created: $(IMAGE_NAME):snapshot" + +# Build and run +dev: build run logs + +# Help +help: + @echo "Available targets:" + @echo " build - Build the Docker image" + @echo " run - Run the container" + @echo " run-hd - Run with 720p resolution" + @echo " run-persist - Run with persistent storage" + @echo " stop - Stop and remove container" + @echo " push - Push to Docker Hub" + @echo " clean - Remove image and container" + @echo " test - Build, run tests, and stop" + @echo " logs - View container logs" + @echo " logs-* - View specific service logs" + @echo " shell - Open shell in container" + @echo " status - Check supervisor status" + @echo " snapshot - Create container snapshot" + @echo " dev - Build, run, and follow logs" diff --git a/libs/docker-xfce/QUICKSTART.md b/libs/docker-xfce/QUICKSTART.md new file mode 100644 index 00000000..9cd8082b --- /dev/null +++ b/libs/docker-xfce/QUICKSTART.md @@ -0,0 +1,166 @@ +# Quick Start Guide + +Get up and running with CUA Docker XFCE in 5 minutes. + +## Prerequisites + +- Docker installed and running +- Python 3.11+ (for using with CUA library) +- `cua-computer` package installed: `pip install cua-computer` + +## Quick Start + +### Option 1: Using Makefile (Recommended) + +```bash +# Build and run +make build +make run + +# Check if it's running +make status + +# View logs +make logs +``` + +Access: +- 🌐 **Web VNC**: http://localhost:6901 +- 🖥️ **VNC Client**: localhost:5901 (password: `password`) +- 🔌 **API**: http://localhost:8000 + +### Option 2: Using Docker Compose + +```bash +# Start the container +docker-compose up -d + +# View logs +docker-compose logs -f + +# Stop the container +docker-compose down +``` + +### Option 3: Docker Command + +```bash +docker run -d \ + --name cua-desktop \ + --shm-size=512m \ + -p 5901:5901 \ + -p 6901:6901 \ + -p 8000:8000 \ + trycua/cua-docker-xfce:latest +``` + +## Using with Python + +```python +import asyncio +from computer import Computer + +async def main(): + computer = Computer( + os_type="linux", + provider_type="docker", + image="trycua/cua-docker-xfce:latest" + ) + + async with computer: + # Take a screenshot + screenshot = await computer.interface.screenshot() + + # Open terminal + await computer.interface.hotkey("ctrl", "alt", "t") + await asyncio.sleep(1) + + # Type and execute command + await computer.interface.type_text("echo 'Hello!'") + await computer.interface.press_key("Return") + +asyncio.run(main()) +``` + +## Common Tasks + +### Run with custom resolution +```bash +make run-hd # 1280x720 +# or +docker run -e VNC_RESOLUTION=1280x720 ... +``` + +### Run with persistent storage +```bash +make run-persist +# or +docker run -v $(pwd)/storage:/home/cua/storage ... +``` + +### View specific logs +```bash +make logs-vnc # VNC server logs +make logs-novnc # noVNC proxy logs +make logs-api # Computer-server logs +``` + +### Open shell in container +```bash +make shell +# or +docker exec -it cua-desktop /bin/bash +``` + +### Create a snapshot +```bash +make snapshot +``` + +## Troubleshooting + +### Container won't start +```bash +# Check if ports are already in use +lsof -i :6901 +lsof -i :8000 + +# View container logs +docker logs cua-desktop +``` + +### Black screen in noVNC +```bash +# Restart VNC server +docker exec cua-desktop supervisorctl restart vncserver +``` + +### API not responding +```bash +# Check if computer-server is running +docker exec cua-desktop supervisorctl status computer-server + +# Restart computer-server +docker exec cua-desktop supervisorctl restart computer-server +``` + +## Next Steps + +- Read the [full README](README.md) for detailed documentation +- Check out [example.py](example.py) for more usage examples +- Customize the [Dockerfile](Dockerfile) for your needs + +## Clean Up + +```bash +# Using Makefile +make clean + +# Using docker-compose +docker-compose down -v + +# Manual +docker stop cua-desktop +docker rm cua-desktop +docker rmi trycua/cua-docker-xfce:latest +``` diff --git a/libs/docker-xfce/README.md b/libs/docker-xfce/README.md new file mode 100644 index 00000000..489d0042 --- /dev/null +++ b/libs/docker-xfce/README.md @@ -0,0 +1,238 @@ +# CUA Docker XFCE Container + +Vanilla XFCE desktop container for Computer-Using Agents (CUA) with noVNC and computer-server. This is a lightweight alternative to the Kasm-based container with minimal dependencies. + +## Features + +- Ubuntu 22.04 (Jammy) with vanilla XFCE desktop environment +- TigerVNC server for remote desktop access +- noVNC for web-based VNC access (no client required) +- Pre-installed computer-server for remote computer control +- Python 3.11 with necessary libraries +- Screen capture tools (gnome-screenshot, wmctrl, ffmpeg) +- Clipboard utilities (xclip, socat) +- Firefox browser with telemetry disabled + +## Architecture + +``` +┌─────────────────────────────────────────┐ +│ Docker Container (Ubuntu 22.04) │ +├─────────────────────────────────────────┤ +│ XFCE Desktop Environment │ +│ ├── Firefox │ +│ ├── XFCE Terminal │ +│ └── Desktop utilities │ +├─────────────────────────────────────────┤ +│ TigerVNC Server (Port 5901) │ +│ └── X11 Display :1 │ +├─────────────────────────────────────────┤ +│ noVNC Web Interface (Port 6901) │ +│ └── WebSocket proxy to VNC │ +├─────────────────────────────────────────┤ +│ CUA Computer Server (Port 8000) │ +│ └── WebSocket API for automation │ +└─────────────────────────────────────────┘ +``` + +## Building the Container + +```bash +docker build -t cua-docker-xfce:latest . +``` + +## Pushing to Registry + +```bash +# Tag for Docker Hub (replace 'trycua' with your Docker Hub username) +docker tag cua-docker-xfce:latest trycua/cua-docker-xfce:latest + +# Login to Docker Hub +docker login + +# Push to Docker Hub +docker push trycua/cua-docker-xfce:latest +``` + +## Running the Container Manually + +### Basic Usage + +```bash +docker run --rm -it \ + --shm-size=512m \ + -p 5901:5901 \ + -p 6901:6901 \ + -p 8000:8000 \ + cua-docker-xfce:latest +``` + +### With Custom Resolution + +```bash +docker run --rm -it \ + --shm-size=512m \ + -p 5901:5901 \ + -p 6901:6901 \ + -p 8000:8000 \ + -e VNC_RESOLUTION=1280x720 \ + cua-docker-xfce:latest +``` + +### With Persistent Storage + +```bash +docker run --rm -it \ + --shm-size=512m \ + -p 5901:5901 \ + -p 6901:6901 \ + -p 8000:8000 \ + -v $(pwd)/storage:/home/cua/storage \ + cua-docker-xfce:latest +``` + +## Accessing the Container + +- **noVNC Web Interface**: Open `http://localhost:6901` in your browser +- **VNC Client**: Connect to `localhost:5901` (password: `password`) +- **Computer Server API**: Available at `http://localhost:8000` + +## Using with CUA Docker Provider + +This container is designed to work with the CUA Docker provider: + +```python +from computer import Computer + +# Create computer with docker-xfce container +computer = Computer( + os_type="linux", + provider_type="docker", + image="trycua/cua-docker-xfce:latest", + display="1920x1080", + memory="4GB", + cpu="2" +) + +# Use the computer +async with computer: + # Take a screenshot + screenshot = await computer.interface.screenshot() + + # Click and type + await computer.interface.left_click(100, 100) + await computer.interface.type_text("Hello from CUA!") + + # Run commands + result = await computer.interface.run_command("ls -la") + print(result.stdout) +``` + +## Environment Variables + +| Variable | Default | Description | +|----------|---------|-------------| +| `VNC_RESOLUTION` | `1920x1080` | Screen resolution | +| `VNC_COL_DEPTH` | `24` | Color depth | +| `VNC_PORT` | `5901` | VNC server port | +| `NOVNC_PORT` | `6901` | noVNC web interface port | +| `API_PORT` | `8000` | Computer-server API port | +| `DISPLAY` | `:1` | X11 display number | + +## Exposed Ports + +- **5901**: TigerVNC server +- **6901**: noVNC web interface +- **8000**: Computer-server WebSocket API + +## Volume Mount Points + +- `/home/cua/storage`: Persistent storage mount point +- `/home/cua/shared`: Shared folder mount point + +## User Credentials + +- **Username**: `cua` +- **Password**: `password` +- **Sudo access**: Enabled without password + +## Creating Snapshots + +### Filesystem Snapshot +```bash +docker commit cua-docker-xfce-snapshot:latest +``` + +### Running from Snapshot +```bash +docker run --rm -it \ + --shm-size=512m \ + -p 6901:6901 \ + -p 8000:8000 \ + cua-docker-xfce-snapshot:latest +``` + +## Comparison with Kasm Container + +| Feature | Kasm Container | Docker XFCE Container | +|---------|---------------|----------------------| +| Base Image | KasmWeb Ubuntu | Vanilla Ubuntu | +| VNC Server | KasmVNC | TigerVNC | +| Dependencies | Higher | Lower | +| Configuration | Pre-configured | Minimal | +| Size | Larger | Smaller | +| Maintenance | Depends on Kasm | Independent | + +## Process Management + +The container uses `supervisord` to manage three main processes: + +1. **VNC Server** (Priority 10): TigerVNC with XFCE desktop +2. **noVNC** (Priority 20): WebSocket proxy for browser access +3. **Computer Server** (Priority 30): CUA automation API + +All processes are automatically restarted on failure. + +## Troubleshooting + +### VNC server won't start +Check if X11 lock files exist: +```bash +docker exec rm -rf /tmp/.X1-lock /tmp/.X11-unix/X1 +``` + +### noVNC shows black screen +Ensure VNC server is running: +```bash +docker exec supervisorctl status vncserver +``` + +### Computer-server not responding +Check if X server is accessible: +```bash +docker exec env DISPLAY=:1 xdpyinfo +``` + +### View logs +```bash +docker exec tail -f /var/log/supervisor/supervisord.log +docker exec supervisorctl status +``` + +## Integration with CUA System + +This container provides the same functionality as the Kasm container but with: +- **Reduced dependencies**: No reliance on KasmWeb infrastructure +- **Smaller image size**: Minimal base configuration +- **Full control**: Direct access to all components +- **Easy customization**: Simple to modify and extend + +The container integrates seamlessly with: +- CUA Computer library (via WebSocket API) +- Docker provider for lifecycle management +- Standard VNC clients for debugging +- Web browsers for visual monitoring + +## License + +MIT License - See LICENSE file for details diff --git a/libs/docker-xfce/docker-compose.yml b/libs/docker-xfce/docker-compose.yml new file mode 100644 index 00000000..bdc1ba2d --- /dev/null +++ b/libs/docker-xfce/docker-compose.yml @@ -0,0 +1,44 @@ +version: '3.8' + +services: + cua-desktop: + build: . + image: trycua/cua-docker-xfce:latest + container_name: cua-docker-xfce + shm_size: '512m' + ports: + - "5901:5901" # VNC + - "6901:6901" # noVNC + - "8000:8000" # Computer API + environment: + - VNC_RESOLUTION=1920x1080 + - VNC_COL_DEPTH=24 + - VNC_PORT=5901 + - NOVNC_PORT=6901 + - API_PORT=8000 + volumes: + - ./storage:/home/cua/storage + - ./shared:/home/cua/shared + restart: unless-stopped + healthcheck: + test: ["CMD", "curl", "-f", "http://localhost:8000"] + interval: 30s + timeout: 10s + retries: 3 + start_period: 40s + + # Optional: Multiple instances for parallel testing + cua-desktop-2: + build: . + image: trycua/cua-docker-xfce:latest + container_name: cua-docker-xfce-2 + shm_size: '512m' + ports: + - "5902:5901" + - "6902:6901" + - "8001:8000" + environment: + - VNC_RESOLUTION=1280x720 + restart: unless-stopped + profiles: + - multi diff --git a/libs/docker-xfce/example.py b/libs/docker-xfce/example.py new file mode 100644 index 00000000..6c42bbc2 --- /dev/null +++ b/libs/docker-xfce/example.py @@ -0,0 +1,213 @@ +#!/usr/bin/env python3 +""" +Example script demonstrating how to use the CUA Docker XFCE container +with the Computer library. +""" + +import asyncio +from computer import Computer + + +async def basic_example(): + """Basic example: Take a screenshot and click around""" + print("=== Basic Example ===") + + computer = Computer( + os_type="linux", + provider_type="docker", + image="trycua/cua-docker-xfce:latest", + display="1920x1080", + memory="4GB", + cpu="2", + port=8000, + noVNC_port=6901 + ) + + async with computer: + print("Computer is ready!") + print(f"noVNC available at: http://localhost:6901") + + # Get screen info + screen = await computer.interface.get_screen_size() + print(f"Screen size: {screen['width']}x{screen['height']}") + + # Take a screenshot + screenshot = await computer.interface.screenshot() + with open("screenshot.png", "wb") as f: + f.write(screenshot) + print("Screenshot saved to screenshot.png") + + # Click and type + await computer.interface.left_click(100, 100) + await computer.interface.type_text("Hello from CUA!") + + print("Done!") + + +async def file_operations_example(): + """Example: File system operations""" + print("\n=== File Operations Example ===") + + computer = Computer( + os_type="linux", + provider_type="docker", + image="trycua/cua-docker-xfce:latest" + ) + + async with computer: + # Create a file + await computer.interface.write_text( + "/home/cua/test.txt", + "Hello from CUA!" + ) + print("Created test.txt") + + # Read it back + content = await computer.interface.read_text("/home/cua/test.txt") + print(f"File content: {content}") + + # List directory + files = await computer.interface.list_dir("/home/cua") + print(f"Files in home directory: {files}") + + +async def command_execution_example(): + """Example: Running shell commands""" + print("\n=== Command Execution Example ===") + + computer = Computer( + os_type="linux", + provider_type="docker", + image="trycua/cua-docker-xfce:latest" + ) + + async with computer: + # Run a command + result = await computer.interface.run_command("uname -a") + print(f"System info:\n{result.stdout}") + + # Check Firefox is installed + result = await computer.interface.run_command("which firefox") + print(f"Firefox location: {result.stdout.strip()}") + + # Get Python version + result = await computer.interface.run_command("python3 --version") + print(f"Python version: {result.stdout.strip()}") + + +async def browser_automation_example(): + """Example: Opening Firefox and navigating""" + print("\n=== Browser Automation Example ===") + + computer = Computer( + os_type="linux", + provider_type="docker", + image="trycua/cua-docker-xfce:latest" + ) + + async with computer: + # Open Firefox + await computer.interface.run_command("firefox https://example.com &") + print("Firefox opened") + + # Wait for it to load + await asyncio.sleep(5) + + # Take a screenshot + screenshot = await computer.interface.screenshot() + with open("browser_screenshot.png", "wb") as f: + f.write(screenshot) + print("Browser screenshot saved") + + +async def persistent_storage_example(): + """Example: Using persistent storage""" + print("\n=== Persistent Storage Example ===") + + computer = Computer( + os_type="linux", + provider_type="docker", + image="trycua/cua-docker-xfce:latest", + shared_directories=["./storage"] + ) + + async with computer: + # Write to persistent storage + await computer.interface.write_text( + "/home/cua/storage/persistent.txt", + "This file persists across container restarts!" + ) + print("Written to persistent storage") + + # Read it back + content = await computer.interface.read_text( + "/home/cua/storage/persistent.txt" + ) + print(f"Content: {content}") + + +async def multi_action_example(): + """Example: Complex interaction sequence""" + print("\n=== Multi-Action Example ===") + + computer = Computer( + os_type="linux", + provider_type="docker", + image="trycua/cua-docker-xfce:latest" + ) + + async with computer: + # Open terminal + await computer.interface.hotkey("ctrl", "alt", "t") + await asyncio.sleep(2) + + # Type a command + await computer.interface.type_text("echo 'Hello from CUA!'") + await computer.interface.press_key("Return") + await asyncio.sleep(1) + + # Take screenshot + screenshot = await computer.interface.screenshot() + with open("terminal_screenshot.png", "wb") as f: + f.write(screenshot) + print("Terminal screenshot saved") + + +async def main(): + """Run all examples""" + examples = [ + ("Basic", basic_example), + ("File Operations", file_operations_example), + ("Command Execution", command_execution_example), + ("Browser Automation", browser_automation_example), + ("Persistent Storage", persistent_storage_example), + ("Multi-Action", multi_action_example), + ] + + print("Available examples:") + for i, (name, _) in enumerate(examples, 1): + print(f"{i}. {name}") + print(f"{len(examples) + 1}. Run all") + + choice = input("\nSelect an example (1-7): ").strip() + + try: + if choice == str(len(examples) + 1): + # Run all examples + for name, func in examples: + try: + await func() + except Exception as e: + print(f"Error in {name}: {e}") + else: + idx = int(choice) - 1 + if 0 <= idx < len(examples): + await examples[idx][1]() + else: + print("Invalid choice") + except ValueError: + print("Invalid input") + + +if __name__ == "__main__": + asyncio.run(main()) diff --git a/libs/docker-xfce/src/scripts/start-computer-server.sh b/libs/docker-xfce/src/scripts/start-computer-server.sh new file mode 100644 index 00000000..bc27a3db --- /dev/null +++ b/libs/docker-xfce/src/scripts/start-computer-server.sh @@ -0,0 +1,13 @@ +#!/bin/bash +set -e + +# Wait for X server to be ready +echo "Waiting for X server to start..." +while ! xdpyinfo -display :1 >/dev/null 2>&1; do + sleep 1 +done +echo "X server is ready" + +# Start computer-server +export DISPLAY=:1 +python3 -m computer_server --port ${API_PORT:-8000} diff --git a/libs/docker-xfce/src/scripts/start-novnc.sh b/libs/docker-xfce/src/scripts/start-novnc.sh new file mode 100644 index 00000000..4f95c644 --- /dev/null +++ b/libs/docker-xfce/src/scripts/start-novnc.sh @@ -0,0 +1,15 @@ +#!/bin/bash +set -e + +# Wait for VNC server to be ready +echo "Waiting for VNC server to start..." +while ! nc -z localhost ${VNC_PORT:-5901}; do + sleep 1 +done +echo "VNC server is ready" + +# Start noVNC +cd /opt/noVNC +/opt/noVNC/utils/novnc_proxy \ + --vnc localhost:${VNC_PORT:-5901} \ + --listen ${NOVNC_PORT:-6901} diff --git a/libs/docker-xfce/src/scripts/start-vnc.sh b/libs/docker-xfce/src/scripts/start-vnc.sh new file mode 100644 index 00000000..1cbba98f --- /dev/null +++ b/libs/docker-xfce/src/scripts/start-vnc.sh @@ -0,0 +1,22 @@ +#!/bin/bash +set -e + +# Clean up any existing VNC lock files +rm -rf /tmp/.X1-lock /tmp/.X11-unix/X1 + +# Start VNC server +vncserver :1 \ + -geometry ${VNC_RESOLUTION:-1920x1080} \ + -depth ${VNC_COL_DEPTH:-24} \ + -rfbport ${VNC_PORT:-5901} \ + -localhost no \ + -SecurityTypes None \ + -AlwaysShared \ + -AcceptPointerEvents \ + -AcceptKeyEvents \ + -AcceptCutText \ + -SendCutText \ + -xstartup /usr/local/bin/xstartup.sh + +# Keep the process running +tail -f /home/cua/.vnc/*.log diff --git a/libs/docker-xfce/src/scripts/xstartup.sh b/libs/docker-xfce/src/scripts/xstartup.sh new file mode 100644 index 00000000..49bb46a2 --- /dev/null +++ b/libs/docker-xfce/src/scripts/xstartup.sh @@ -0,0 +1,21 @@ +#!/bin/bash +set -e + +# Start D-Bus +if [ -z "$DBUS_SESSION_BUS_ADDRESS" ]; then + eval $(dbus-launch --sh-syntax --exit-with-session) +fi + +# Start XFCE +startxfce4 & + +# Wait for XFCE to start +sleep 2 + +# Disable screensaver and power management +xset s off +xset -dpms +xset s noblank + +# Wait for the session +wait diff --git a/libs/docker-xfce/src/supervisor/supervisord.conf b/libs/docker-xfce/src/supervisor/supervisord.conf new file mode 100644 index 00000000..fb367c4f --- /dev/null +++ b/libs/docker-xfce/src/supervisor/supervisord.conf @@ -0,0 +1,30 @@ +[supervisord] +nodaemon=true +user=root +logfile=/var/log/supervisor/supervisord.log +pidfile=/var/run/supervisord.pid +childlogdir=/var/log/supervisor + +[program:vncserver] +command=/usr/local/bin/start-vnc.sh +user=cua +autorestart=true +stdout_logfile=/var/log/supervisor/vncserver.log +stderr_logfile=/var/log/supervisor/vncserver.error.log +priority=10 + +[program:novnc] +command=/usr/local/bin/start-novnc.sh +user=cua +autorestart=true +stdout_logfile=/var/log/supervisor/novnc.log +stderr_logfile=/var/log/supervisor/novnc.error.log +priority=20 + +[program:computer-server] +command=/usr/local/bin/start-computer-server.sh +user=cua +autorestart=true +stdout_logfile=/var/log/supervisor/computer-server.log +stderr_logfile=/var/log/supervisor/computer-server.error.log +priority=30 From 05c3356f1919f108cb0ef14e489925db7be0c335 Mon Sep 17 00:00:00 2001 From: f-trycua Date: Fri, 10 Oct 2025 12:41:09 -0700 Subject: [PATCH 02/10] Fix Docker XFCE container build and VNC startup MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Fixed two critical issues: 1. Firefox syspref.js was being created as directory instead of file - Changed mkdir to create parent directory only - Use > for first echo to create file 2. TigerVNC refusing to start without authentication - Changed SecurityTypes from None to VncAuth - Added --I-KNOW-THIS-IS-INSECURE flag for development Container now successfully: - Builds on ARM64 Mac - Starts all services (VNC, noVNC, computer-server) - Accessible on ports 5901 (VNC), 6901 (noVNC), 8000 (API) Also added Dockerfile.slim as lighter alternative. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude --- libs/docker-xfce/Dockerfile | 11 +---- libs/docker-xfce/Dockerfile.slim | 53 +++++++++++++++++++++++ libs/docker-xfce/src/scripts/start-vnc.sh | 5 ++- 3 files changed, 58 insertions(+), 11 deletions(-) create mode 100644 libs/docker-xfce/Dockerfile.slim diff --git a/libs/docker-xfce/Dockerfile b/libs/docker-xfce/Dockerfile index 94326ae2..d5459f31 100644 --- a/libs/docker-xfce/Dockerfile +++ b/libs/docker-xfce/Dockerfile @@ -38,7 +38,6 @@ RUN apt-get update && apt-get install -y \ net-tools \ supervisor \ # Computer-server dependencies - python3.11 \ python3-tk \ python3-dev \ gnome-screenshot \ @@ -62,12 +61,6 @@ RUN apt-get update && apt-get install -y \ zlib1g-dev \ && rm -rf /var/lib/apt/lists/* -# Install Python 3.11 -RUN add-apt-repository ppa:deadsnakes/ppa && \ - apt-get update && \ - apt-get install -y python3.11 python3.11-distutils && \ - rm -rf /var/lib/apt/lists/* - # Install noVNC RUN git clone https://github.com/novnc/noVNC.git /opt/noVNC && \ git clone https://github.com/novnc/websockify /opt/noVNC/utils/websockify && \ @@ -84,8 +77,8 @@ RUN add-apt-repository -y ppa:mozillateam/ppa && \ rm -rf /var/lib/apt/lists/* # Configure Firefox defaults -RUN mkdir -p /etc/firefox/syspref.js && \ - echo 'pref("datareporting.policy.firstRunURL", "");' >> /etc/firefox/syspref.js && \ +RUN mkdir -p /etc/firefox && \ + echo 'pref("datareporting.policy.firstRunURL", "");' > /etc/firefox/syspref.js && \ echo 'pref("datareporting.policy.dataSubmissionEnabled", false);' >> /etc/firefox/syspref.js && \ echo 'pref("datareporting.healthreport.service.enabled", false);' >> /etc/firefox/syspref.js && \ echo 'pref("datareporting.healthreport.uploadEnabled", false);' >> /etc/firefox/syspref.js && \ diff --git a/libs/docker-xfce/Dockerfile.slim b/libs/docker-xfce/Dockerfile.slim new file mode 100644 index 00000000..51c2233d --- /dev/null +++ b/libs/docker-xfce/Dockerfile.slim @@ -0,0 +1,53 @@ +# CUA Docker XFCE Container - Slim Version +# Uses existing VNC base to reduce build time + +FROM dorowu/ubuntu-desktop-lxde-vnc:focal + +# Switch to root +USER root + +# Set environment variables +ENV HOME=/home/cua +ENV DISPLAY=:1 +ENV API_PORT=8000 + +# Create cua user +RUN useradd -m -s /bin/bash -G sudo cua && \ + echo "cua:password" | chpasswd && \ + echo "cua ALL=(ALL) NOPASSWD:ALL" >> /etc/sudoers + +# Install Python 3.11 and computer-server dependencies +RUN apt-get update && apt-get install -y \ + software-properties-common \ + gnome-screenshot \ + wmctrl \ + ffmpeg \ + socat \ + xclip \ + && add-apt-repository ppa:deadsnakes/ppa \ + && apt-get update \ + && apt-get install -y python3.11 python3-pip \ + && rm -rf /var/lib/apt/lists/* + +# Install computer-server +RUN pip3 install cua-computer-server + +# Copy startup scripts +COPY src/scripts/start-computer-server.sh /usr/local/bin/ +RUN chmod +x /usr/local/bin/start-computer-server.sh + +# Create storage directories +RUN mkdir -p /home/cua/storage /home/cua/shared && \ + chown -R cua:cua /home/cua + +# Expose ports (VNC on 6080, computer-server on 8000) +EXPOSE 6080 8000 + +# Create startup wrapper +RUN echo '#!/bin/bash\n\ +/startup.sh &\n\ +sleep 5\n\ +su - cua -c "/usr/local/bin/start-computer-server.sh"' > /entrypoint.sh && \ + chmod +x /entrypoint.sh + +CMD ["/entrypoint.sh"] diff --git a/libs/docker-xfce/src/scripts/start-vnc.sh b/libs/docker-xfce/src/scripts/start-vnc.sh index 1cbba98f..f77afef0 100644 --- a/libs/docker-xfce/src/scripts/start-vnc.sh +++ b/libs/docker-xfce/src/scripts/start-vnc.sh @@ -10,13 +10,14 @@ vncserver :1 \ -depth ${VNC_COL_DEPTH:-24} \ -rfbport ${VNC_PORT:-5901} \ -localhost no \ - -SecurityTypes None \ + -SecurityTypes VncAuth \ -AlwaysShared \ -AcceptPointerEvents \ -AcceptKeyEvents \ -AcceptCutText \ -SendCutText \ - -xstartup /usr/local/bin/xstartup.sh + -xstartup /usr/local/bin/xstartup.sh \ + --I-KNOW-THIS-IS-INSECURE # Keep the process running tail -f /home/cua/.vnc/*.log From 09049096f494cfb4d26255d9ef72e8375bd7674b Mon Sep 17 00:00:00 2001 From: f-trycua Date: Fri, 10 Oct 2025 16:14:11 -0700 Subject: [PATCH 03/10] Fix noVNC startup by removing netcat dependency MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Changed start-novnc.sh to use a simple sleep instead of checking VNC availability with netcat. This avoids the need to install netcat and simplifies the startup sequence. Since supervisor starts services in priority order (VNC=10, noVNC=20), a 5-second sleep is sufficient for VNC to be ready. Also added netcat to Dockerfile for future use if needed. Container now fully functional: - VNC server running on port 5901 - noVNC web interface on port 6901 - Computer-server API on port 8000 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude --- libs/docker-xfce/Dockerfile | 1 + libs/docker-xfce/src/scripts/start-novnc.sh | 7 ++----- 2 files changed, 3 insertions(+), 5 deletions(-) diff --git a/libs/docker-xfce/Dockerfile b/libs/docker-xfce/Dockerfile index d5459f31..2721d599 100644 --- a/libs/docker-xfce/Dockerfile +++ b/libs/docker-xfce/Dockerfile @@ -36,6 +36,7 @@ RUN apt-get update && apt-get install -y \ python3-numpy \ git \ net-tools \ + netcat \ supervisor \ # Computer-server dependencies python3-tk \ diff --git a/libs/docker-xfce/src/scripts/start-novnc.sh b/libs/docker-xfce/src/scripts/start-novnc.sh index 4f95c644..07894acb 100644 --- a/libs/docker-xfce/src/scripts/start-novnc.sh +++ b/libs/docker-xfce/src/scripts/start-novnc.sh @@ -1,12 +1,9 @@ #!/bin/bash set -e -# Wait for VNC server to be ready +# Give VNC a moment to start (supervisor starts it with priority 10, this is priority 20) echo "Waiting for VNC server to start..." -while ! nc -z localhost ${VNC_PORT:-5901}; do - sleep 1 -done -echo "VNC server is ready" +sleep 5 # Start noVNC cd /opt/noVNC From 6e780ac3452128e6231f688fbfcd6297eb650582 Mon Sep 17 00:00:00 2001 From: f-trycua Date: Fri, 10 Oct 2025 18:03:21 -0700 Subject: [PATCH 04/10] Remove XFCE power manager to prevent startup popup MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Uninstall xfce4-power-manager package which causes annoying popup dialog on container startup. Power management is not needed in a containerized environment. This provides a cleaner desktop experience on first launch. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude --- libs/docker-xfce/Dockerfile | 3 +++ 1 file changed, 3 insertions(+) diff --git a/libs/docker-xfce/Dockerfile b/libs/docker-xfce/Dockerfile index 2721d599..17c4b962 100644 --- a/libs/docker-xfce/Dockerfile +++ b/libs/docker-xfce/Dockerfile @@ -62,6 +62,9 @@ RUN apt-get update && apt-get install -y \ zlib1g-dev \ && rm -rf /var/lib/apt/lists/* +# Remove power manager to avoid popup in container +RUN apt-get remove -y xfce4-power-manager xfce4-power-manager-data || true + # Install noVNC RUN git clone https://github.com/novnc/noVNC.git /opt/noVNC && \ git clone https://github.com/novnc/websockify /opt/noVNC/utils/websockify && \ From a9866f831ae767135e84994d582674c8a67d5e5e Mon Sep 17 00:00:00 2001 From: f-trycua Date: Fri, 10 Oct 2025 18:07:36 -0700 Subject: [PATCH 05/10] Remove Firefox to speed up container build MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Firefox installation was causing very slow builds (1200+ seconds) downloading 72MB on ARM. Removed it since it's not essential for the basic container functionality. Firefox can be installed later inside the running container if needed: docker exec cua-docker-xfce apt-get install -y firefox Build time reduced from 20+ minutes to under 1 minute. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude --- libs/docker-xfce/Dockerfile | 16 ++-------------- 1 file changed, 2 insertions(+), 14 deletions(-) diff --git a/libs/docker-xfce/Dockerfile b/libs/docker-xfce/Dockerfile index 17c4b962..12b890a5 100644 --- a/libs/docker-xfce/Dockerfile +++ b/libs/docker-xfce/Dockerfile @@ -73,20 +73,8 @@ RUN git clone https://github.com/novnc/noVNC.git /opt/noVNC && \ # Install computer-server RUN pip3 install cua-computer-server -# Install Firefox -RUN add-apt-repository -y ppa:mozillateam/ppa && \ - echo 'Package: *\nPin: release o=LP-PPA-mozillateam\nPin-Priority: 1001' > /etc/apt/preferences.d/mozilla-firefox && \ - apt-get update && \ - apt-get install -y firefox && \ - rm -rf /var/lib/apt/lists/* - -# Configure Firefox defaults -RUN mkdir -p /etc/firefox && \ - echo 'pref("datareporting.policy.firstRunURL", "");' > /etc/firefox/syspref.js && \ - echo 'pref("datareporting.policy.dataSubmissionEnabled", false);' >> /etc/firefox/syspref.js && \ - echo 'pref("datareporting.healthreport.service.enabled", false);' >> /etc/firefox/syspref.js && \ - echo 'pref("datareporting.healthreport.uploadEnabled", false);' >> /etc/firefox/syspref.js && \ - echo 'pref("browser.aboutwelcome.enabled", false);' >> /etc/firefox/syspref.js +# Firefox installation removed to speed up build +# Can be added back later if needed # Copy startup scripts COPY src/supervisor/ /etc/supervisor/conf.d/ From 86c5642128335241a47394192a8605b030e90847 Mon Sep 17 00:00:00 2001 From: f-trycua Date: Fri, 10 Oct 2025 18:13:14 -0700 Subject: [PATCH 06/10] Add Firefox back using Ubuntu default repository MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Install Firefox from Ubuntu's default repository instead of the Mozilla PPA. This is much faster (3 minutes vs 20+ minutes) and installs the snap version which works well in containers. Container now includes: - XFCE desktop (no power manager popup) - Firefox browser - VNC/noVNC access - Computer-server API Build time: ~3-4 minutes total 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude --- libs/docker-xfce/Dockerfile | 1 + 1 file changed, 1 insertion(+) diff --git a/libs/docker-xfce/Dockerfile b/libs/docker-xfce/Dockerfile index 12b890a5..d854c876 100644 --- a/libs/docker-xfce/Dockerfile +++ b/libs/docker-xfce/Dockerfile @@ -47,6 +47,7 @@ RUN apt-get update && apt-get install -y \ socat \ xclip \ # Browser + firefox \ wget \ software-properties-common \ # Build tools From e88099aea417bb6ff6b8bdefd845a575164e023c Mon Sep 17 00:00:00 2001 From: f-trycua Date: Fri, 10 Oct 2025 21:02:42 -0700 Subject: [PATCH 07/10] Cleanup --- libs/docker-xfce/Dockerfile | 37 ++++++++++--- libs/docker-xfce/Dockerfile.slim | 53 ------------------- .../docker-xfce/src/scripts/resize-display.sh | 20 +++++++ libs/docker-xfce/src/xfce-config/helpers.rc | 2 + .../src/xfce-config/xfce4-session.xml | 51 ++++++++++++++++++ 5 files changed, 103 insertions(+), 60 deletions(-) delete mode 100644 libs/docker-xfce/Dockerfile.slim create mode 100644 libs/docker-xfce/src/scripts/resize-display.sh create mode 100644 libs/docker-xfce/src/xfce-config/helpers.rc create mode 100644 libs/docker-xfce/src/xfce-config/xfce4-session.xml diff --git a/libs/docker-xfce/Dockerfile b/libs/docker-xfce/Dockerfile index d854c876..02d48eb2 100644 --- a/libs/docker-xfce/Dockerfile +++ b/libs/docker-xfce/Dockerfile @@ -12,7 +12,7 @@ ENV DISPLAY=:1 ENV VNC_PORT=5901 ENV NOVNC_PORT=6901 ENV API_PORT=8000 -ENV VNC_RESOLUTION=1920x1080 +ENV VNC_RESOLUTION=1024x768 ENV VNC_COL_DEPTH=24 # Create user @@ -47,7 +47,6 @@ RUN apt-get update && apt-get install -y \ socat \ xclip \ # Browser - firefox \ wget \ software-properties-common \ # Build tools @@ -66,16 +65,31 @@ RUN apt-get update && apt-get install -y \ # Remove power manager to avoid popup in container RUN apt-get remove -y xfce4-power-manager xfce4-power-manager-data || true +# Install Firefox from Mozilla PPA (snap-free) - inline to avoid script issues +RUN apt-get update && \ + add-apt-repository -y ppa:mozillateam/ppa && \ + echo 'Package: *\nPin: release o=LP-PPA-mozillateam\nPin-Priority: 1001' > /etc/apt/preferences.d/mozilla-firefox && \ + apt-get update && \ + apt-get install -y firefox && \ + echo 'pref("datareporting.policy.firstRunURL", "");\npref("datareporting.policy.dataSubmissionEnabled", false);\npref("datareporting.healthreport.service.enabled", false);\npref("datareporting.healthreport.uploadEnabled", false);\npref("trailhead.firstrun.branches", "nofirstrun-empty");\npref("browser.aboutwelcome.enabled", false);' > /usr/lib/firefox/browser/defaults/preferences/firefox.js && \ + update-alternatives --install /usr/bin/x-www-browser x-www-browser /usr/bin/firefox 100 && \ + update-alternatives --install /usr/bin/gnome-www-browser gnome-www-browser /usr/bin/firefox 100 && \ + rm -rf /var/lib/apt/lists/* + # Install noVNC RUN git clone https://github.com/novnc/noVNC.git /opt/noVNC && \ git clone https://github.com/novnc/websockify /opt/noVNC/utils/websockify && \ ln -s /opt/noVNC/vnc.html /opt/noVNC/index.html +# Pre-create cache directory with correct ownership before pip install +RUN mkdir -p /home/cua/.cache && \ + chown -R cua:cua /home/cua/.cache + # Install computer-server RUN pip3 install cua-computer-server -# Firefox installation removed to speed up build -# Can be added back later if needed +# Fix any cache files created by pip +RUN chown -R cua:cua /home/cua/.cache # Copy startup scripts COPY src/supervisor/ /etc/supervisor/conf.d/ @@ -94,10 +108,19 @@ RUN mkdir -p $HOME/.vnc && \ chmod 600 $HOME/.vnc/passwd # Configure XFCE for first start -RUN mkdir -p $HOME/.config/xfce4/xfconf/xfce-perchannel-xml +RUN mkdir -p $HOME/.config/xfce4/xfconf/xfce-perchannel-xml $HOME/.config/xfce4 $HOME/.config/autostart -# Create storage and shared directories -RUN mkdir -p $HOME/storage $HOME/shared +# Copy XFCE config to disable browser launching and welcome screens +COPY --chown=cua:cua src/xfce-config/helpers.rc $HOME/.config/xfce4/helpers.rc +COPY --chown=cua:cua src/xfce-config/xfce4-session.xml $HOME/.config/xfce4/xfconf/xfce-perchannel-xml/xfce4-session.xml + +# Disable panel plugins that might try to open browsers +RUN echo "[Desktop Entry]\nHidden=true" > $HOME/.config/autostart/xfce4-tips-autostart.desktop && \ + chown -R cua:cua $HOME/.config + +# Create storage and shared directories, and Firefox cache directory +RUN mkdir -p $HOME/storage $HOME/shared $HOME/.cache/dconf $HOME/.mozilla/firefox && \ + chown -R cua:cua $HOME/storage $HOME/shared $HOME/.cache $HOME/.mozilla $HOME/.vnc USER root diff --git a/libs/docker-xfce/Dockerfile.slim b/libs/docker-xfce/Dockerfile.slim deleted file mode 100644 index 51c2233d..00000000 --- a/libs/docker-xfce/Dockerfile.slim +++ /dev/null @@ -1,53 +0,0 @@ -# CUA Docker XFCE Container - Slim Version -# Uses existing VNC base to reduce build time - -FROM dorowu/ubuntu-desktop-lxde-vnc:focal - -# Switch to root -USER root - -# Set environment variables -ENV HOME=/home/cua -ENV DISPLAY=:1 -ENV API_PORT=8000 - -# Create cua user -RUN useradd -m -s /bin/bash -G sudo cua && \ - echo "cua:password" | chpasswd && \ - echo "cua ALL=(ALL) NOPASSWD:ALL" >> /etc/sudoers - -# Install Python 3.11 and computer-server dependencies -RUN apt-get update && apt-get install -y \ - software-properties-common \ - gnome-screenshot \ - wmctrl \ - ffmpeg \ - socat \ - xclip \ - && add-apt-repository ppa:deadsnakes/ppa \ - && apt-get update \ - && apt-get install -y python3.11 python3-pip \ - && rm -rf /var/lib/apt/lists/* - -# Install computer-server -RUN pip3 install cua-computer-server - -# Copy startup scripts -COPY src/scripts/start-computer-server.sh /usr/local/bin/ -RUN chmod +x /usr/local/bin/start-computer-server.sh - -# Create storage directories -RUN mkdir -p /home/cua/storage /home/cua/shared && \ - chown -R cua:cua /home/cua - -# Expose ports (VNC on 6080, computer-server on 8000) -EXPOSE 6080 8000 - -# Create startup wrapper -RUN echo '#!/bin/bash\n\ -/startup.sh &\n\ -sleep 5\n\ -su - cua -c "/usr/local/bin/start-computer-server.sh"' > /entrypoint.sh && \ - chmod +x /entrypoint.sh - -CMD ["/entrypoint.sh"] diff --git a/libs/docker-xfce/src/scripts/resize-display.sh b/libs/docker-xfce/src/scripts/resize-display.sh new file mode 100644 index 00000000..ea663dce --- /dev/null +++ b/libs/docker-xfce/src/scripts/resize-display.sh @@ -0,0 +1,20 @@ +#!/bin/bash +# Dynamic display resolution script +# Can be called to change the VNC display resolution + +RESOLUTION=${1:-1920x1080} + +# Wait for display to be ready +for i in {1..10}; do + if DISPLAY=:1 xdpyinfo >/dev/null 2>&1; then + break + fi + sleep 1 +done + +# Change resolution using xrandr +DISPLAY=:1 xrandr --output VNC-0 --mode "$RESOLUTION" 2>/dev/null || \ +DISPLAY=:1 xrandr --fb "$RESOLUTION" 2>/dev/null || \ +echo "Failed to set resolution to $RESOLUTION" + +echo "Display resolution set to: $RESOLUTION" diff --git a/libs/docker-xfce/src/xfce-config/helpers.rc b/libs/docker-xfce/src/xfce-config/helpers.rc new file mode 100644 index 00000000..8fd42f69 --- /dev/null +++ b/libs/docker-xfce/src/xfce-config/helpers.rc @@ -0,0 +1,2 @@ +# XFCE preferred applications - disable browser to prevent error popups +WebBrowser= diff --git a/libs/docker-xfce/src/xfce-config/xfce4-session.xml b/libs/docker-xfce/src/xfce-config/xfce4-session.xml new file mode 100644 index 00000000..d7b834d9 --- /dev/null +++ b/libs/docker-xfce/src/xfce-config/xfce4-session.xml @@ -0,0 +1,51 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + From 3053270f74420a97627a8866c3e48b28330b0889 Mon Sep 17 00:00:00 2001 From: f-trycua Date: Sat, 11 Oct 2025 11:03:50 -0700 Subject: [PATCH 08/10] Add XFCE provider --- libs/docker-xfce/README.md | 30 +++++++++++++--- .../computer/providers/docker/provider.py | 36 ++++++++++++++----- 2 files changed, 54 insertions(+), 12 deletions(-) diff --git a/libs/docker-xfce/README.md b/libs/docker-xfce/README.md index 489d0042..5d8512c8 100644 --- a/libs/docker-xfce/README.md +++ b/libs/docker-xfce/README.md @@ -99,7 +99,7 @@ docker run --rm -it \ ## Using with CUA Docker Provider -This container is designed to work with the CUA Docker provider: +This container is designed to work with the CUA Docker provider. Simply specify the docker-xfce image: ```python from computer import Computer @@ -108,8 +108,8 @@ from computer import Computer computer = Computer( os_type="linux", provider_type="docker", - image="trycua/cua-docker-xfce:latest", - display="1920x1080", + image="trycua/cua-docker-xfce:latest", # Use docker-xfce instead of Kasm + display="1024x768", memory="4GB", cpu="2" ) @@ -128,11 +128,33 @@ async with computer: print(result.stdout) ``` +### Switching between Kasm and docker-xfce + +The Docker provider automatically detects which image you're using: + +```python +# Use Kasm-based container (default for Linux) +computer_kasm = Computer( + os_type="linux", + provider_type="docker", + image="trycua/cua-ubuntu:latest", # Kasm image +) + +# Use docker-xfce container (vanilla XFCE) +computer_xfce = Computer( + os_type="linux", + provider_type="docker", + image="trycua/cua-docker-xfce:latest", # docker-xfce image +) +``` + +Both provide the same API and functionality - the provider automatically configures the correct paths and settings based on the image. + ## Environment Variables | Variable | Default | Description | |----------|---------|-------------| -| `VNC_RESOLUTION` | `1920x1080` | Screen resolution | +| `VNC_RESOLUTION` | `1024x768` | Screen resolution | | `VNC_COL_DEPTH` | `24` | Color depth | | `VNC_PORT` | `5901` | VNC server port | | `NOVNC_PORT` | `6901` | noVNC web interface port | diff --git a/libs/python/computer/computer/providers/docker/provider.py b/libs/python/computer/computer/providers/docker/provider.py index 82ad411c..487edc28 100644 --- a/libs/python/computer/computer/providers/docker/provider.py +++ b/libs/python/computer/computer/providers/docker/provider.py @@ -36,7 +36,7 @@ class DockerProvider(BaseVMProvider): """ def __init__( - self, + self, port: Optional[int] = 8000, host: str = "localhost", storage: Optional[str] = None, @@ -47,13 +47,16 @@ class DockerProvider(BaseVMProvider): vnc_port: Optional[int] = 6901, ): """Initialize the Docker VM Provider. - + Args: port: Currently unused (VM provider port) host: Hostname for the API server (default: localhost) storage: Path for persistent VM storage shared_path: Path for shared folder between host and container image: Docker image to use (default: "trycua/cua-ubuntu:latest") + Supported images: + - "trycua/cua-ubuntu:latest" (Kasm-based) + - "trycua/cua-docker-xfce:latest" (vanilla XFCE) verbose: Enable verbose logging ephemeral: Use ephemeral (temporary) storage vnc_port: Port for VNC interface (default: 6901) @@ -62,19 +65,35 @@ class DockerProvider(BaseVMProvider): self.api_port = 8000 self.vnc_port = vnc_port self.ephemeral = ephemeral - + # Handle ephemeral storage (temporary directory) if ephemeral: self.storage = "ephemeral" else: self.storage = storage - + self.shared_path = shared_path self.image = image self.verbose = verbose self._container_id = None self._running_containers = {} # Track running containers by name + + # Detect image type and configure user directory accordingly + self._detect_image_config() + def _detect_image_config(self): + """Detect image type and configure paths accordingly.""" + # Detect if this is a docker-xfce image or Kasm image + if "docker-xfce" in self.image.lower() or "xfce" in self.image.lower(): + self._home_dir = "/home/cua" + self._image_type = "docker-xfce" + logger.info(f"Detected docker-xfce image: using {self._home_dir}") + else: + # Default to Kasm configuration + self._home_dir = "/home/kasm-user" + self._image_type = "kasm" + logger.info(f"Detected Kasm image: using {self._home_dir}") + @property def provider_type(self) -> VMProviderType: """Return the provider type.""" @@ -277,12 +296,13 @@ class DockerProvider(BaseVMProvider): # Add volume mounts if storage is specified storage_path = storage or self.storage if storage_path and storage_path != "ephemeral": - # Mount storage directory - cmd.extend(["-v", f"{storage_path}:/home/kasm-user/storage"]) - + # Mount storage directory using detected home directory + cmd.extend(["-v", f"{storage_path}:{self._home_dir}/storage"]) + # Add shared path if specified if self.shared_path: - cmd.extend(["-v", f"{self.shared_path}:/home/kasm-user/shared"]) + # Mount shared directory using detected home directory + cmd.extend(["-v", f"{self.shared_path}:{self._home_dir}/shared"]) # Add environment variables cmd.extend(["-e", "VNC_PW=password"]) # Set VNC password From 7b286f77c6e1cf842df96ddd7b0a64fda8f10ff5 Mon Sep 17 00:00:00 2001 From: f-trycua Date: Sat, 11 Oct 2025 21:51:00 -0700 Subject: [PATCH 09/10] Set default browser --- libs/docker-xfce/Dockerfile | 20 ++++++++++---------- libs/docker-xfce/README.md | 7 ++++--- libs/docker-xfce/src/scripts/start-vnc.sh | 4 ++-- libs/docker-xfce/src/xfce-config/helpers.rc | 4 ++-- 4 files changed, 18 insertions(+), 17 deletions(-) diff --git a/libs/docker-xfce/Dockerfile b/libs/docker-xfce/Dockerfile index 02d48eb2..f6411919 100644 --- a/libs/docker-xfce/Dockerfile +++ b/libs/docker-xfce/Dockerfile @@ -15,13 +15,10 @@ ENV API_PORT=8000 ENV VNC_RESOLUTION=1024x768 ENV VNC_COL_DEPTH=24 -# Create user -RUN useradd -m -s /bin/bash -G sudo cua && \ - echo "cua:password" | chpasswd && \ - echo "cua ALL=(ALL) NOPASSWD:ALL" >> /etc/sudoers - -# Install system dependencies +# Install system dependencies first (including sudo) RUN apt-get update && apt-get install -y \ + # System utilities + sudo \ # Desktop environment xfce4 \ xfce4-terminal \ @@ -65,6 +62,11 @@ RUN apt-get update && apt-get install -y \ # Remove power manager to avoid popup in container RUN apt-get remove -y xfce4-power-manager xfce4-power-manager-data || true +# Create user after sudo is installed +RUN useradd -m -s /bin/bash -G sudo cua && \ + echo "cua:password" | chpasswd && \ + echo "cua ALL=(ALL) NOPASSWD:ALL" >> /etc/sudoers + # Install Firefox from Mozilla PPA (snap-free) - inline to avoid script issues RUN apt-get update && \ add-apt-repository -y ppa:mozillateam/ppa && \ @@ -102,10 +104,8 @@ RUN chmod +x /usr/local/bin/*.sh USER cua WORKDIR /home/cua -# Create VNC password file -RUN mkdir -p $HOME/.vnc && \ - echo "password" | vncpasswd -f > $HOME/.vnc/passwd && \ - chmod 600 $HOME/.vnc/passwd +# Create VNC directory (no password needed with SecurityTypes None) +RUN mkdir -p $HOME/.vnc # Configure XFCE for first start RUN mkdir -p $HOME/.config/xfce4/xfconf/xfce-perchannel-xml $HOME/.config/xfce4 $HOME/.config/autostart diff --git a/libs/docker-xfce/README.md b/libs/docker-xfce/README.md index 5d8512c8..9ecdff00 100644 --- a/libs/docker-xfce/README.md +++ b/libs/docker-xfce/README.md @@ -93,8 +93,8 @@ docker run --rm -it \ ## Accessing the Container -- **noVNC Web Interface**: Open `http://localhost:6901` in your browser -- **VNC Client**: Connect to `localhost:5901` (password: `password`) +- **noVNC Web Interface**: Open `http://localhost:6901` in your browser (no password required) +- **VNC Client**: Connect to `localhost:5901` (no password required) - **Computer Server API**: Available at `http://localhost:8000` ## Using with CUA Docker Provider @@ -175,8 +175,9 @@ Both provide the same API and functionality - the provider automatically configu ## User Credentials - **Username**: `cua` -- **Password**: `password` +- **Password**: `password` (for shell login only) - **Sudo access**: Enabled without password +- **VNC access**: No password required ## Creating Snapshots diff --git a/libs/docker-xfce/src/scripts/start-vnc.sh b/libs/docker-xfce/src/scripts/start-vnc.sh index f77afef0..934e6d3c 100644 --- a/libs/docker-xfce/src/scripts/start-vnc.sh +++ b/libs/docker-xfce/src/scripts/start-vnc.sh @@ -4,13 +4,13 @@ set -e # Clean up any existing VNC lock files rm -rf /tmp/.X1-lock /tmp/.X11-unix/X1 -# Start VNC server +# Start VNC server without password authentication vncserver :1 \ -geometry ${VNC_RESOLUTION:-1920x1080} \ -depth ${VNC_COL_DEPTH:-24} \ -rfbport ${VNC_PORT:-5901} \ -localhost no \ - -SecurityTypes VncAuth \ + -SecurityTypes None \ -AlwaysShared \ -AcceptPointerEvents \ -AcceptKeyEvents \ diff --git a/libs/docker-xfce/src/xfce-config/helpers.rc b/libs/docker-xfce/src/xfce-config/helpers.rc index 8fd42f69..b2270633 100644 --- a/libs/docker-xfce/src/xfce-config/helpers.rc +++ b/libs/docker-xfce/src/xfce-config/helpers.rc @@ -1,2 +1,2 @@ -# XFCE preferred applications - disable browser to prevent error popups -WebBrowser= +# XFCE preferred applications - set Firefox as default browser +WebBrowser=firefox From 1a83931587eece82aca0b83b522d39277e689cc2 Mon Sep 17 00:00:00 2001 From: f-trycua Date: Sat, 11 Oct 2025 22:14:00 -0700 Subject: [PATCH 10/10] Remove unused --- libs/docker-xfce/LICENSE | 21 --- libs/docker-xfce/Makefile | 127 ----------------- libs/docker-xfce/QUICKSTART.md | 166 ---------------------- libs/docker-xfce/docker-compose.yml | 44 ------ libs/docker-xfce/example.py | 213 ---------------------------- 5 files changed, 571 deletions(-) delete mode 100644 libs/docker-xfce/LICENSE delete mode 100644 libs/docker-xfce/Makefile delete mode 100644 libs/docker-xfce/QUICKSTART.md delete mode 100644 libs/docker-xfce/docker-compose.yml delete mode 100644 libs/docker-xfce/example.py diff --git a/libs/docker-xfce/LICENSE b/libs/docker-xfce/LICENSE deleted file mode 100644 index 6899a9db..00000000 --- a/libs/docker-xfce/LICENSE +++ /dev/null @@ -1,21 +0,0 @@ -MIT License - -Copyright (c) 2025 CUA - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -SOFTWARE. diff --git a/libs/docker-xfce/Makefile b/libs/docker-xfce/Makefile deleted file mode 100644 index e3aa2879..00000000 --- a/libs/docker-xfce/Makefile +++ /dev/null @@ -1,127 +0,0 @@ -.PHONY: build run stop push clean test logs shell - -IMAGE_NAME := trycua/cua-docker-xfce -TAG := latest -CONTAINER_NAME := cua-docker-xfce-test - -# Build the Docker image -build: - docker build -t $(IMAGE_NAME):$(TAG) . - -# Run the container -run: - docker run -d \ - --name $(CONTAINER_NAME) \ - --shm-size=512m \ - -p 5901:5901 \ - -p 6901:6901 \ - -p 8000:8000 \ - $(IMAGE_NAME):$(TAG) - @echo "Container started!" - @echo "noVNC: http://localhost:6901" - @echo "VNC: localhost:5901 (password: password)" - @echo "API: http://localhost:8000" - -# Run with custom resolution -run-hd: - docker run -d \ - --name $(CONTAINER_NAME) \ - --shm-size=512m \ - -p 5901:5901 \ - -p 6901:6901 \ - -p 8000:8000 \ - -e VNC_RESOLUTION=1280x720 \ - $(IMAGE_NAME):$(TAG) - -# Run with persistent storage -run-persist: - mkdir -p ./storage ./shared - docker run -d \ - --name $(CONTAINER_NAME) \ - --shm-size=512m \ - -p 5901:5901 \ - -p 6901:6901 \ - -p 8000:8000 \ - -v $(PWD)/storage:/home/cua/storage \ - -v $(PWD)/shared:/home/cua/shared \ - $(IMAGE_NAME):$(TAG) - -# Stop and remove the container -stop: - docker stop $(CONTAINER_NAME) || true - docker rm $(CONTAINER_NAME) || true - -# Push to Docker Hub -push: - docker push $(IMAGE_NAME):$(TAG) - -# Clean up everything -clean: stop - docker rmi $(IMAGE_NAME):$(TAG) || true - rm -rf ./storage ./shared - -# Run tests -test: build run - @echo "Waiting for services to start..." - @sleep 10 - @echo "Testing noVNC..." - @curl -f http://localhost:6901 > /dev/null && echo "✓ noVNC is running" || echo "✗ noVNC failed" - @echo "Testing API..." - @curl -f http://localhost:8000 > /dev/null && echo "✓ API is running" || echo "✗ API failed" - @$(MAKE) stop - -# View logs -logs: - docker logs -f $(CONTAINER_NAME) - -# View supervisor logs -logs-supervisor: - docker exec $(CONTAINER_NAME) tail -f /var/log/supervisor/supervisord.log - -# View individual service logs -logs-vnc: - docker exec $(CONTAINER_NAME) tail -f /var/log/supervisor/vncserver.log - -logs-novnc: - docker exec $(CONTAINER_NAME) tail -f /var/log/supervisor/novnc.log - -logs-api: - docker exec $(CONTAINER_NAME) tail -f /var/log/supervisor/computer-server.log - -# Open a shell in the container -shell: - docker exec -it $(CONTAINER_NAME) /bin/bash - -# Check supervisor status -status: - docker exec $(CONTAINER_NAME) supervisorctl status - -# Restart services -restart-services: - docker exec $(CONTAINER_NAME) supervisorctl restart all - -# Create a snapshot -snapshot: - docker commit $(CONTAINER_NAME) $(IMAGE_NAME):snapshot - @echo "Snapshot created: $(IMAGE_NAME):snapshot" - -# Build and run -dev: build run logs - -# Help -help: - @echo "Available targets:" - @echo " build - Build the Docker image" - @echo " run - Run the container" - @echo " run-hd - Run with 720p resolution" - @echo " run-persist - Run with persistent storage" - @echo " stop - Stop and remove container" - @echo " push - Push to Docker Hub" - @echo " clean - Remove image and container" - @echo " test - Build, run tests, and stop" - @echo " logs - View container logs" - @echo " logs-* - View specific service logs" - @echo " shell - Open shell in container" - @echo " status - Check supervisor status" - @echo " snapshot - Create container snapshot" - @echo " dev - Build, run, and follow logs" diff --git a/libs/docker-xfce/QUICKSTART.md b/libs/docker-xfce/QUICKSTART.md deleted file mode 100644 index 9cd8082b..00000000 --- a/libs/docker-xfce/QUICKSTART.md +++ /dev/null @@ -1,166 +0,0 @@ -# Quick Start Guide - -Get up and running with CUA Docker XFCE in 5 minutes. - -## Prerequisites - -- Docker installed and running -- Python 3.11+ (for using with CUA library) -- `cua-computer` package installed: `pip install cua-computer` - -## Quick Start - -### Option 1: Using Makefile (Recommended) - -```bash -# Build and run -make build -make run - -# Check if it's running -make status - -# View logs -make logs -``` - -Access: -- 🌐 **Web VNC**: http://localhost:6901 -- 🖥️ **VNC Client**: localhost:5901 (password: `password`) -- 🔌 **API**: http://localhost:8000 - -### Option 2: Using Docker Compose - -```bash -# Start the container -docker-compose up -d - -# View logs -docker-compose logs -f - -# Stop the container -docker-compose down -``` - -### Option 3: Docker Command - -```bash -docker run -d \ - --name cua-desktop \ - --shm-size=512m \ - -p 5901:5901 \ - -p 6901:6901 \ - -p 8000:8000 \ - trycua/cua-docker-xfce:latest -``` - -## Using with Python - -```python -import asyncio -from computer import Computer - -async def main(): - computer = Computer( - os_type="linux", - provider_type="docker", - image="trycua/cua-docker-xfce:latest" - ) - - async with computer: - # Take a screenshot - screenshot = await computer.interface.screenshot() - - # Open terminal - await computer.interface.hotkey("ctrl", "alt", "t") - await asyncio.sleep(1) - - # Type and execute command - await computer.interface.type_text("echo 'Hello!'") - await computer.interface.press_key("Return") - -asyncio.run(main()) -``` - -## Common Tasks - -### Run with custom resolution -```bash -make run-hd # 1280x720 -# or -docker run -e VNC_RESOLUTION=1280x720 ... -``` - -### Run with persistent storage -```bash -make run-persist -# or -docker run -v $(pwd)/storage:/home/cua/storage ... -``` - -### View specific logs -```bash -make logs-vnc # VNC server logs -make logs-novnc # noVNC proxy logs -make logs-api # Computer-server logs -``` - -### Open shell in container -```bash -make shell -# or -docker exec -it cua-desktop /bin/bash -``` - -### Create a snapshot -```bash -make snapshot -``` - -## Troubleshooting - -### Container won't start -```bash -# Check if ports are already in use -lsof -i :6901 -lsof -i :8000 - -# View container logs -docker logs cua-desktop -``` - -### Black screen in noVNC -```bash -# Restart VNC server -docker exec cua-desktop supervisorctl restart vncserver -``` - -### API not responding -```bash -# Check if computer-server is running -docker exec cua-desktop supervisorctl status computer-server - -# Restart computer-server -docker exec cua-desktop supervisorctl restart computer-server -``` - -## Next Steps - -- Read the [full README](README.md) for detailed documentation -- Check out [example.py](example.py) for more usage examples -- Customize the [Dockerfile](Dockerfile) for your needs - -## Clean Up - -```bash -# Using Makefile -make clean - -# Using docker-compose -docker-compose down -v - -# Manual -docker stop cua-desktop -docker rm cua-desktop -docker rmi trycua/cua-docker-xfce:latest -``` diff --git a/libs/docker-xfce/docker-compose.yml b/libs/docker-xfce/docker-compose.yml deleted file mode 100644 index bdc1ba2d..00000000 --- a/libs/docker-xfce/docker-compose.yml +++ /dev/null @@ -1,44 +0,0 @@ -version: '3.8' - -services: - cua-desktop: - build: . - image: trycua/cua-docker-xfce:latest - container_name: cua-docker-xfce - shm_size: '512m' - ports: - - "5901:5901" # VNC - - "6901:6901" # noVNC - - "8000:8000" # Computer API - environment: - - VNC_RESOLUTION=1920x1080 - - VNC_COL_DEPTH=24 - - VNC_PORT=5901 - - NOVNC_PORT=6901 - - API_PORT=8000 - volumes: - - ./storage:/home/cua/storage - - ./shared:/home/cua/shared - restart: unless-stopped - healthcheck: - test: ["CMD", "curl", "-f", "http://localhost:8000"] - interval: 30s - timeout: 10s - retries: 3 - start_period: 40s - - # Optional: Multiple instances for parallel testing - cua-desktop-2: - build: . - image: trycua/cua-docker-xfce:latest - container_name: cua-docker-xfce-2 - shm_size: '512m' - ports: - - "5902:5901" - - "6902:6901" - - "8001:8000" - environment: - - VNC_RESOLUTION=1280x720 - restart: unless-stopped - profiles: - - multi diff --git a/libs/docker-xfce/example.py b/libs/docker-xfce/example.py deleted file mode 100644 index 6c42bbc2..00000000 --- a/libs/docker-xfce/example.py +++ /dev/null @@ -1,213 +0,0 @@ -#!/usr/bin/env python3 -""" -Example script demonstrating how to use the CUA Docker XFCE container -with the Computer library. -""" - -import asyncio -from computer import Computer - - -async def basic_example(): - """Basic example: Take a screenshot and click around""" - print("=== Basic Example ===") - - computer = Computer( - os_type="linux", - provider_type="docker", - image="trycua/cua-docker-xfce:latest", - display="1920x1080", - memory="4GB", - cpu="2", - port=8000, - noVNC_port=6901 - ) - - async with computer: - print("Computer is ready!") - print(f"noVNC available at: http://localhost:6901") - - # Get screen info - screen = await computer.interface.get_screen_size() - print(f"Screen size: {screen['width']}x{screen['height']}") - - # Take a screenshot - screenshot = await computer.interface.screenshot() - with open("screenshot.png", "wb") as f: - f.write(screenshot) - print("Screenshot saved to screenshot.png") - - # Click and type - await computer.interface.left_click(100, 100) - await computer.interface.type_text("Hello from CUA!") - - print("Done!") - - -async def file_operations_example(): - """Example: File system operations""" - print("\n=== File Operations Example ===") - - computer = Computer( - os_type="linux", - provider_type="docker", - image="trycua/cua-docker-xfce:latest" - ) - - async with computer: - # Create a file - await computer.interface.write_text( - "/home/cua/test.txt", - "Hello from CUA!" - ) - print("Created test.txt") - - # Read it back - content = await computer.interface.read_text("/home/cua/test.txt") - print(f"File content: {content}") - - # List directory - files = await computer.interface.list_dir("/home/cua") - print(f"Files in home directory: {files}") - - -async def command_execution_example(): - """Example: Running shell commands""" - print("\n=== Command Execution Example ===") - - computer = Computer( - os_type="linux", - provider_type="docker", - image="trycua/cua-docker-xfce:latest" - ) - - async with computer: - # Run a command - result = await computer.interface.run_command("uname -a") - print(f"System info:\n{result.stdout}") - - # Check Firefox is installed - result = await computer.interface.run_command("which firefox") - print(f"Firefox location: {result.stdout.strip()}") - - # Get Python version - result = await computer.interface.run_command("python3 --version") - print(f"Python version: {result.stdout.strip()}") - - -async def browser_automation_example(): - """Example: Opening Firefox and navigating""" - print("\n=== Browser Automation Example ===") - - computer = Computer( - os_type="linux", - provider_type="docker", - image="trycua/cua-docker-xfce:latest" - ) - - async with computer: - # Open Firefox - await computer.interface.run_command("firefox https://example.com &") - print("Firefox opened") - - # Wait for it to load - await asyncio.sleep(5) - - # Take a screenshot - screenshot = await computer.interface.screenshot() - with open("browser_screenshot.png", "wb") as f: - f.write(screenshot) - print("Browser screenshot saved") - - -async def persistent_storage_example(): - """Example: Using persistent storage""" - print("\n=== Persistent Storage Example ===") - - computer = Computer( - os_type="linux", - provider_type="docker", - image="trycua/cua-docker-xfce:latest", - shared_directories=["./storage"] - ) - - async with computer: - # Write to persistent storage - await computer.interface.write_text( - "/home/cua/storage/persistent.txt", - "This file persists across container restarts!" - ) - print("Written to persistent storage") - - # Read it back - content = await computer.interface.read_text( - "/home/cua/storage/persistent.txt" - ) - print(f"Content: {content}") - - -async def multi_action_example(): - """Example: Complex interaction sequence""" - print("\n=== Multi-Action Example ===") - - computer = Computer( - os_type="linux", - provider_type="docker", - image="trycua/cua-docker-xfce:latest" - ) - - async with computer: - # Open terminal - await computer.interface.hotkey("ctrl", "alt", "t") - await asyncio.sleep(2) - - # Type a command - await computer.interface.type_text("echo 'Hello from CUA!'") - await computer.interface.press_key("Return") - await asyncio.sleep(1) - - # Take screenshot - screenshot = await computer.interface.screenshot() - with open("terminal_screenshot.png", "wb") as f: - f.write(screenshot) - print("Terminal screenshot saved") - - -async def main(): - """Run all examples""" - examples = [ - ("Basic", basic_example), - ("File Operations", file_operations_example), - ("Command Execution", command_execution_example), - ("Browser Automation", browser_automation_example), - ("Persistent Storage", persistent_storage_example), - ("Multi-Action", multi_action_example), - ] - - print("Available examples:") - for i, (name, _) in enumerate(examples, 1): - print(f"{i}. {name}") - print(f"{len(examples) + 1}. Run all") - - choice = input("\nSelect an example (1-7): ").strip() - - try: - if choice == str(len(examples) + 1): - # Run all examples - for name, func in examples: - try: - await func() - except Exception as e: - print(f"Error in {name}: {e}") - else: - idx = int(choice) - 1 - if 0 <= idx < len(examples): - await examples[idx][1]() - else: - print("Invalid choice") - except ValueError: - print("Invalid input") - - -if __name__ == "__main__": - asyncio.run(main())