diff --git a/docker-compose.yml b/docker-compose.yml index f5bbbce..452699d 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -1,32 +1,47 @@ version: '3.8' services: - vps-agent: - build: . - container_name: vps-ai-agent - restart: unless-stopped - expose: - - "8001" - ports: - - "8001:8001" - # Monta as credenciais e o socket do docker para o Bot conseguir comandar a VPS raiz! - volumes: - - .:/app - - /var/run/docker.sock:/var/run/docker.sock:rw - - /:/host_root:ro # Acesso em leitura à VPS para análise - - ./data:/app/data # Configs dinâmicas (API Keys, etc) - env_file: - - .env - networks: - - coolify - - ollama_net - labels: - - "traefik.enable=true" - - "traefik.http.routers.vps-agent.rule=Host(`claw.reifonas.cloud`)" - - "traefik.http.routers.vps-agent.entrypoints=https" - - "traefik.http.routers.vps-agent.tls=true" - - "traefik.http.routers.vps-agent.tls.certresolver=letsencrypt" - - "traefik.http.services.vps-agent.loadbalancer.server.port=8001" + vps-agent: + build: . + container_name: vps-ai-agent + restart: unless-stopped + expose: + - "8001" + ports: + - "8001:8001" + volumes: + - .:/app + - /var/run/docker.sock:/var/run/docker.sock:rw + - /:/host_root:ro + - ./data:/app/data + env_file: + - .env + networks: + - coolify + - ollama_net + labels: + - "traefik.enable=true" + - "traefik.http.routers.vps-agent.rule=Host(`claw.reifonas.cloud`)" + - "traefik.http.routers.vps-agent.entrypoints=https" + - "traefik.http.routers.vps-agent.tls=true" + - "traefik.http.routers.vps-agent.tls.certresolver=letsencrypt" + - "traefik.http.services.vps-agent.loadbalancer.server.port=8001" + + vnc: + build: ./vnc + container_name: vps-vnc + restart: unless-stopped + ports: + - "6080:6080" + volumes: + - /tmp/.X11-unix:/tmp/.X11-unix:rw + networks: + - coolify + labels: + - "traefik.enable=true" + - "traefik.http.routers.vnc.rule=Host(`vnc.claw.reifonas.cloud`)" + - "traefik.http.routers.vnc.entrypoints=http" + - "traefik.http.services.vnc.loadbalancer.server.port=6080" networks: coolify: diff --git a/main.py b/main.py index a3848e1..3779da7 100644 --- a/main.py +++ b/main.py @@ -120,8 +120,23 @@ async def run_action(data: dict, is_auth: bool = Depends(verify_password)): return {"status": "success", "message": "Cache do servidor limpo com sucesso."} if action_type == "reboot_vps": return {"status": "error", "message": "⚠️ Reboot via Web desabilitado por segurança. Use o terminal SSH."} + if action_type == "toggle_vnc": + import subprocess + result = subprocess.run(["docker", "ps", "-q", "-f", "name=vps-vnc"], capture_output=True, text=True) + if result.stdout.strip(): + subprocess.run(["docker", "stop", "vps-vnc"], capture_output=True) + return {"status": "success", "message": "VNC desligado.", "vnc_status": "off"} + else: + subprocess.run(["docker", "start", "vps-vnc"], capture_output=True) + return {"status": "success", "message": "VNC ligado. https://vnc.claw.reifonas.cloud/vnc.html", "vnc_status": "on"} return {"status": "error", "message": f"Ação {action_type} desconhecida."} +@app.get("/api/vnc_status") +async def vnc_status(): + import subprocess + result = subprocess.run(["docker", "ps", "-q", "-f", "name=vps-vnc"], capture_output=True, text=True) + return {"vnc_status": "on" if result.stdout.strip() else "off"} + @app.get("/api/test_llm") async def test_llm_latency(is_auth: bool = Depends(verify_password)): t0 = time.time() diff --git a/templates/index.html b/templates/index.html index 5cec2aa..da7fd35 100644 --- a/templates/index.html +++ b/templates/index.html @@ -767,13 +767,21 @@ Limpar Cache - - + + +
Configuração AI
@@ -969,14 +977,31 @@ return res; } - function initDashboard() { - fetchStats(); - loadConfig(); - loadOrchestratorStatus(); - loadLLMModels().then(function() { - loadLLMConfig(); - }); - } + function initDashboard() { + fetchStats(); + loadConfig(); + loadOrchestratorStatus(); + loadVNCStatus(); + loadLLMModels().then(function() { + loadLLMConfig(); + }); + } + + async function loadVNCStatus() { + try { + const res = await apiFetch('/api/vnc_status'); + const data = await res.json(); + const btn = document.getElementById('vnc-toggle-btn'); + const txt = document.getElementById('vnc-toggle-text'); + if (data.vnc_status === 'on') { + txt.textContent = 'Desligar VNC'; + btn.classList.add('btn-success'); + } else { + txt.textContent = 'Ligar VNC'; + btn.classList.remove('btn-success'); + } + } catch (e) {} + } // Theme management function toggleTheme() { @@ -1049,11 +1074,12 @@ // Actions async function executeAction(type) { - const messages = { - reboot_vps: '⚠️ Confirma reboot CRÍTICO da VPS?', - clear_cache: 'Limpar cache do servidor?', - restart_bot: 'Reiniciar o agente AI?' - }; + const messages = { + reboot_vps: '⚠️ Confirma reboot CRÍTICO da VPS?', + clear_cache: 'Limpar cache do servidor?', + restart_bot: 'Reiniciar o agente AI?', + toggle_vnc: null + }; if (messages[type] && !confirm(messages[type])) return; diff --git a/vnc/Dockerfile b/vnc/Dockerfile new file mode 100644 index 0000000..c9ba8bb --- /dev/null +++ b/vnc/Dockerfile @@ -0,0 +1,23 @@ +FROM debian:bookworm-slim + +RUN apt-get update && apt-get install -y \ + x11vnc xvfb \ + novnc websockify \ + && rm -rf /var/lib/apt/lists/* + +RUN mkdir -p /VNC && cd /VNC \ + && ln -sf /usr/share/novnc/vnc.html vnc.html \ + && ln -sf /usr/share/novnc/vnc_lite.html vnc_lite.html + +# X11 socket from host (display :10) +# Host / is mounted at /host_root by BotVPS compose +VOLUME ["/tmp/.X11-unix:/host_x11/X11-unix:rw"] + +ENV DISPLAY=:10 + +COPY docker-entrypoint.sh /entrypoint.sh +RUN chmod +x /entrypoint.sh + +EXPOSE 6080 + +ENTRYPOINT ["/entrypoint.sh"] diff --git a/vnc/docker-entrypoint.sh b/vnc/docker-entrypoint.sh new file mode 100644 index 0000000..dff41a9 --- /dev/null +++ b/vnc/docker-entrypoint.sh @@ -0,0 +1,26 @@ +#!/bin/bash +set -e + +# Ensure X11 socket exists and has correct permissions +chmod 1777 /tmp/.X11-unix 2>/dev/null || true +chmod 666 /tmp/.X11-unix/X10 2>/dev/null || true + +# Start x11vnc — connects to host XFCE on display :10 +x11vnc \ + -display :10 \ + -nopw \ + -bg \ + -listen 0.0.0.0 \ + -xkb \ + -ncache 10 \ + -ncache_cr \ + -forever \ + -shared \ + -noshm \ + -rfbport 5900 + +# Start websockify → WebSocket proxy for noVNC +exec websockify \ + --web /usr/share/novnc \ + 0.0.0.0:6080 \ + localhost:5900