# syntax=docker/dockerfile:1 FROM ubuntu:22.04 ENV DEBIAN_FRONTEND=noninteractive ENV HOSTNAME=Ubuntu ENV DISPLAY=:99 # ---- Base packages & Desktop Environment ---- RUN apt-get update && apt-get install -y --no-install-recommends \ ca-certificates \ curl \ wget \ git \ sudo \ docker.io \ htop \ btop \ neovim \ lsof \ python3 \ python3-pip \ nginx \ supervisor \ gnupg \ xvfb \ x11vnc \ fluxbox \ novnc \ websockify \ dbus-x11 \ libnss3 \ libatk1.0-0 \ libatk-bridge2.0-0 \ libcups2 \ libdrm2 \ libxkbcommon0 \ libxcomposite1 \ libxdamage1 \ libxfixes3 \ libxrandr2 \ libgbm1 \ libpango-1.0-0 \ libcairo2 \ libasound2 \ libgtk-3-0 \ libx11-xcb1 \ libxss1 \ && rm -rf /var/lib/apt/lists/* # Map noVNC entrypoint so the user doesn't have to navigate directories in the browser RUN ln -s /usr/share/novnc/vnc.html /usr/share/novnc/index.html # ---- Install Google Antigravity ---- RUN wget -qO antigravity.deb "https://antigravity.google/download/linux?format=deb" && \ apt-get update && apt-get install -y ./antigravity.deb && \ rm antigravity.deb && \ rm -rf /var/lib/apt/lists/* # ---- Install API Dependencies ---- RUN pip3 install fastapi uvicorn pydantic # ---- Setup Directories ---- RUN mkdir -p /opt/api /workspace /var/log/supervisor /root/.vnc # ---- 1. Create the Python API (FastAPI) ---- COPY <<"EOF" /opt/api/api.py from fastapi import FastAPI, HTTPException from pydantic import BaseModel import os, subprocess, shutil app = FastAPI() class WriteRequest(BaseModel): path: str content: str class ExecRequest(BaseModel): command: str class DeleteRequest(BaseModel): path: str @app.get('/api/list') def list_dir(path: str = '/workspace'): try: return {'files': os.listdir(path)} except Exception as e: raise HTTPException(status_code=400, detail=str(e)) @app.get('/api/read') def read_file(path: str): try: with open(path, 'r', encoding='utf-8') as f: return {'content': f.read()} except Exception as e: raise HTTPException(status_code=400, detail=str(e)) @app.post('/api/write') def write_file(req: WriteRequest): try: os.makedirs(os.path.dirname(req.path), exist_ok=True) with open(req.path, 'w', encoding='utf-8') as f: f.write(req.content) return {'status': 'success'} except Exception as e: raise HTTPException(status_code=400, detail=str(e)) @app.post('/api/exec') def exec_cmd(req: ExecRequest): try: result = subprocess.run(req.command, shell=True, capture_output=True, text=True) return {'stdout': result.stdout, 'stderr': result.stderr, 'returncode': result.returncode} except Exception as e: raise HTTPException(status_code=400, detail=str(e)) @app.post('/api/delete') def delete_item(req: DeleteRequest): try: if os.path.isdir(req.path): shutil.rmtree(req.path) else: os.remove(req.path) return {'status': 'success'} except Exception as e: raise HTTPException(status_code=400, detail=str(e)) EOF # ---- 2. Create Nginx Configuration ---- COPY <<"EOF" /etc/nginx/nginx.conf events {} http { server { listen 7860; # Route API requests to Python server location /api/ { proxy_pass http://127.0.0.1:8000; proxy_set_header Host $host; proxy_set_header X-Real-IP $remote_addr; } # Route all other requests to noVNC location / { proxy_pass http://127.0.0.1:6080/; proxy_set_header Host $host; proxy_set_header Upgrade $http_upgrade; proxy_set_header Connection upgrade; proxy_set_header Accept-Encoding gzip; } } } EOF # ---- 3. Create Supervisor Configuration ---- COPY <<"EOF" /etc/supervisor/conf.d/supervisord.conf[supervisord] nodaemon=true [program:xvfb] command=Xvfb :99 -screen 0 1920x1080x24 -ac +extension GLX +render -noreset priority=10 autorestart=true [program:fluxbox] command=fluxbox environment=DISPLAY=":99" priority=20 autorestart=true[program:x11vnc] command=x11vnc -display :99 -nopw -forever -shared -bg -xkb priority=30 autorestart=true [program:novnc] command=websockify --web /usr/share/novnc 6080 localhost:5900 priority=40 autorestart=true [program:antigravity] command=antigravity --no-sandbox --disable-dev-shm-usage environment=DISPLAY=":99" directory=/workspace priority=50 autorestart=true [program:api] command=uvicorn api:app --host 127.0.0.1 --port 8000 directory=/opt/api priority=60 autorestart=true [program:nginx] command=nginx -g "daemon off;" priority=70 autorestart=true EOF # ---- Workspace Setup ---- WORKDIR /workspace EXPOSE 7860 # Start Supervisor (which automatically handles Xvfb, VNC, noVNC, Antigravity, API, and Nginx) CMD["/usr/bin/supervisord", "-c", "/etc/supervisor/conf.d/supervisord.conf"]