From b388d9fab3bdfeaf2b1e8bd7180ea96bd578541d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=9A=D0=BE=D0=B1=D1=8B=D0=BB=D0=BA=D0=B5=D0=B2=D0=B8?= =?UTF-8?q?=D1=87=20=D0=A4=D1=91=D0=B4=D0=BE=D1=80?= Date: Thu, 2 Apr 2026 09:22:22 +0300 Subject: [PATCH 1/3] update entrypoint and makes profile for remote setup in docker-compose.yml --- READ.md | 18 ++++++++++++++++-- browser_env/entrypoint.sh | 19 ++++++++++++++++--- docker-compose.yml | 2 ++ 3 files changed, 34 insertions(+), 5 deletions(-) diff --git a/READ.md b/READ.md index 41abd358..cba691cd 100644 --- a/READ.md +++ b/READ.md @@ -6,16 +6,30 @@ git clone https://git.lambda.coredump.ru/APEX/BrowserUse_and_ComputerUse_skills. git switch feature/telegram-browser-integration touch .env ``` + В создавшемся .env файле заполните переменные в соответствии с шаблоном, расположенном в .env.example BROWSER_VIEW_URL заполняется после запуска + +#### Запуск удаленно + ```commandline -docker compose up -d --build +docker compose --profile remote up docker compose logs tunnel ``` После команды логов листаешь терминал и ищешь ссылку https в рамке. Её вписываешь в переменную BROWSER_VIEW_URL. -Чтобы увидеть действия агента, переходишь по данной сслыке и выбираешь vnc.html. +Чтобы увидеть действия агента, переходишь по данной ссылке и выбираешь vnc.html. Далее в мессенджере просишь агента сделать что-то через tool browser-use. Возможно придётся перезапустить контейнеры, но при перезапуске контейнеров меняется ссылка. + +#### Запуск локально + +BROWSER_VIEW_URL устанавливается как http://localhost:6080 + +```commandline +docker compose up +``` + +--- ```commandline docker compose down docker compose up -d diff --git a/browser_env/entrypoint.sh b/browser_env/entrypoint.sh index 6d88936b..0b3dddcd 100644 --- a/browser_env/entrypoint.sh +++ b/browser_env/entrypoint.sh @@ -17,10 +17,20 @@ socat TCP-LISTEN:9222,fork,reuseaddr TCP:127.0.0.1:9223 & echo "--- Запуск Chromium в режиме Local-Only (Port 9223) ---" +cleanup() { + echo "Получен сигнал завершения, закрываем Chromium..." + kill $CHROME_PID 2>/dev/null || true + kill $XVFB_PID 2>/dev/null || true + kill $DBUS_PID 2>/dev/null || true + exit 0 +} + +trap cleanup SIGTERM SIGINT + while true; do rm -f /src/browser_data/SingletonLock - chromium \ + DISPLAY=:99 chromium \ --no-sandbox \ --disable-dev-shm-usage \ --remote-debugging-port=9223 \ @@ -34,8 +44,11 @@ while true; do --mute-audio \ --no-default-browser-check \ --disable-software-rasterizer \ - --disable-features=site-per-process + --disable-features=site-per-process & - echo "Chromium упал или был закрыт агентом, рестарт через 2 секунды..." + CHROME_PID=$! + wait $CHROME_PID 2>/dev/null || true + + echo "Chromium завершен, рестарт через 2 секунды..." sleep 2 done \ No newline at end of file diff --git a/docker-compose.yml b/docker-compose.yml index 1ddf1baa..79fa825f 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -53,6 +53,8 @@ services: tunnel: image: cloudflare/cloudflared:latest + profiles: + - remote container_name: hermes-tunnel restart: always command: tunnel --protocol http2 --url http://browser:6080 --no-tls-verify From 9432abee65e968f4cfdb2cf007f68d543afd9ffb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=9A=D0=BE=D0=B1=D1=8B=D0=BB=D0=BA=D0=B5=D0=B2=D0=B8?= =?UTF-8?q?=D1=87=20=D0=A4=D1=91=D0=B4=D0=BE=D1=80?= Date: Thu, 2 Apr 2026 11:55:18 +0300 Subject: [PATCH 2/3] edit entrypoint.sh --- READ.md | 2 +- browser_env/entrypoint.sh | 201 ++++++++++++++++++++++++++++++++------ 2 files changed, 170 insertions(+), 33 deletions(-) diff --git a/READ.md b/READ.md index cba691cd..3eb1421c 100644 --- a/READ.md +++ b/READ.md @@ -13,7 +13,7 @@ BROWSER_VIEW_URL заполняется после запуска #### Запуск удаленно ```commandline -docker compose --profile remote up +docker compose --profile remote up --build docker compose logs tunnel ``` После команды логов листаешь терминал и ищешь ссылку https в рамке. Её вписываешь в переменную BROWSER_VIEW_URL. diff --git a/browser_env/entrypoint.sh b/browser_env/entrypoint.sh index 0b3dddcd..e35c57da 100644 --- a/browser_env/entrypoint.sh +++ b/browser_env/entrypoint.sh @@ -1,54 +1,191 @@ -#!/bin/bash +#!/usr/bin/env bash +set -Eeuo pipefail -export DISPLAY=:99 +export DISPLAY="${DISPLAY:-:99}" +DISPLAY_NUM="${DISPLAY#:}" +XVFB_LOG="/tmp/xvfb.log" -mkdir -p /var/run/dbus -dbus-uuidgen > /var/lib/dbus/machine-id -dbus-daemon --config-file=/usr/share/dbus-1/system.conf --print-address & +VNC_PORT="${VNC_PORT:-5900}" +NOVNC_PORT="${NOVNC_PORT:-6080}" +CHROME_LOCAL_DEBUG_PORT="${CHROME_LOCAL_DEBUG_PORT:-9223}" +CHROME_PUBLIC_DEBUG_PORT="${CHROME_PUBLIC_DEBUG_PORT:-9222}" +CHROME_PROFILE_DIR="${CHROME_PROFILE_DIR:-/src/browser_data}" -Xvfb :99 -screen 0 1280x720x16 -ac +extension GLX +render -noreset & -sleep 2 +MAX_RESTARTS="${MAX_RESTARTS:-10}" +RESTART_WINDOW_SEC="${RESTART_WINDOW_SEC:-60}" +RESTART_BACKOFF_SEC="${RESTART_BACKOFF_SEC:-2}" -fluxbox & -x11vnc -display :99 -nopw -listen 0.0.0.0 -xkb -forever -shared & -websockify --web=/usr/share/novnc/ 6080 localhost:5900 & +PIDS=() +STOPPING=0 +WINDOW_START="$(date +%s)" +RESTART_COUNT=0 -socat TCP-LISTEN:9222,fork,reuseaddr TCP:127.0.0.1:9223 & - -echo "--- Запуск Chromium в режиме Local-Only (Port 9223) ---" - -cleanup() { - echo "Получен сигнал завершения, закрываем Chromium..." - kill $CHROME_PID 2>/dev/null || true - kill $XVFB_PID 2>/dev/null || true - kill $DBUS_PID 2>/dev/null || true - exit 0 +log() { + printf '[%s] %s\n' "$(date '+%Y-%m-%d %H:%M:%S')" "$*" } -trap cleanup SIGTERM SIGINT +start_bg() { + "$@" & + local pid=$! + PIDS+=("$pid") + log "started: $* (pid=$pid)" +} + +wait_for_port() { + local host=$1 + local port=$2 + local timeout_sec=$3 + local end_ts=$(( $(date +%s) + timeout_sec )) + + while [ "$(date +%s)" -lt "$end_ts" ]; do + if bash -c "/dev/null 2>&1; then + return 0 + fi + sleep 0.2 + done + return 1 +} + +wait_for_x_display() { + local timeout_sec=$1 + local end_ts=$(( $(date +%s) + timeout_sec )) + + while [ "$(date +%s)" -lt "$end_ts" ]; do + if [ -S "/tmp/.X11-unix/X${DISPLAY_NUM}" ] && DISPLAY="$DISPLAY" bash -c 'echo >/dev/null' >/dev/null 2>&1; then + return 0 + fi + sleep 0.2 + done + return 1 +} + +cleanup() { + if [ "$STOPPING" -eq 1 ]; then + return + fi + STOPPING=1 + + log "shutdown signal received, stopping processes..." + + if [ -n "${CHROME_PID:-}" ] && kill -0 "$CHROME_PID" >/dev/null 2>&1; then + kill "$CHROME_PID" >/dev/null 2>&1 || true + fi + + for pid in "${PIDS[@]:-}"; do + kill "$pid" >/dev/null 2>&1 || true + done + + sleep 1 + + if [ -n "${CHROME_PID:-}" ] && kill -0 "$CHROME_PID" >/dev/null 2>&1; then + kill -9 "$CHROME_PID" >/dev/null 2>&1 || true + fi + + for pid in "${PIDS[@]:-}"; do + if kill -0 "$pid" >/dev/null 2>&1; then + kill -9 "$pid" >/dev/null 2>&1 || true + fi + done + + log "shutdown complete" +} + +trap cleanup SIGTERM SIGINT EXIT + +mkdir -p /var/run/dbus /var/lib/dbus "$CHROME_PROFILE_DIR" +if [ ! -f /var/lib/dbus/machine-id ]; then + dbus-uuidgen > /var/lib/dbus/machine-id 2>/dev/null || true +fi + +# Удаляем stale lock/socket от прошлых падений Xvfb на том же DISPLAY. +rm -f "/tmp/.X${DISPLAY_NUM}-lock" "/tmp/.X11-unix/X${DISPLAY_NUM}" || true + +log "starting X stack on DISPLAY=${DISPLAY}" +Xvfb "$DISPLAY" -screen 0 1280x720x24 -ac +extension GLX +render -noreset >"$XVFB_LOG" 2>&1 & +XVFB_PID=$! +PIDS+=("$XVFB_PID") +log "started: Xvfb $DISPLAY (pid=$XVFB_PID)" + +if ! wait_for_x_display 15; then + log "fatal: Xvfb did not initialize DISPLAY=${DISPLAY}" + if [ -f "$XVFB_LOG" ]; then + log "xvfb log tail:" + tail -n 40 "$XVFB_LOG" || true + fi + exit 1 +fi + +start_bg fluxbox +start_bg x11vnc -display "$DISPLAY" -rfbport "$VNC_PORT" -nopw -listen 0.0.0.0 -xkb -forever -shared +start_bg websockify --web=/usr/share/novnc/ "$NOVNC_PORT" "localhost:${VNC_PORT}" +start_bg socat "TCP-LISTEN:${CHROME_PUBLIC_DEBUG_PORT},fork,reuseaddr" "TCP:127.0.0.1:${CHROME_LOCAL_DEBUG_PORT}" + +if ! wait_for_port 127.0.0.1 "$VNC_PORT" 20; then + log "fatal: x11vnc did not open port ${VNC_PORT}" + exit 1 +fi +if ! wait_for_port 127.0.0.1 "$NOVNC_PORT" 20; then + log "fatal: websockify did not open port ${NOVNC_PORT}" + exit 1 +fi + +log "browser infrastructure is ready (noVNC:${NOVNC_PORT}, DevTools proxy:${CHROME_PUBLIC_DEBUG_PORT})" while true; do - rm -f /src/browser_data/SingletonLock - - DISPLAY=:99 chromium \ + for pid in "${PIDS[@]}"; do + if ! kill -0 "$pid" >/dev/null 2>&1; then + log "fatal: required background process died (pid=${pid})" + exit 1 + fi + done + + rm -f "${CHROME_PROFILE_DIR}/SingletonLock" "${CHROME_PROFILE_DIR}/SingletonCookie" "${CHROME_PROFILE_DIR}/SingletonSocket" 2>/dev/null || true + + log "starting Chromium (local DevTools:${CHROME_LOCAL_DEBUG_PORT})" + chromium \ --no-sandbox \ --disable-dev-shm-usage \ - --remote-debugging-port=9223 \ + --ozone-platform=x11 \ + --remote-debugging-port="${CHROME_LOCAL_DEBUG_PORT}" \ --remote-debugging-address=127.0.0.1 \ - --remote-allow-origins=* \ + --remote-allow-origins='*' \ --window-size=1280,720 \ - --user-data-dir=/src/browser_data \ + --user-data-dir="${CHROME_PROFILE_DIR}" \ --disable-blink-features=AutomationControlled \ --no-first-run \ --disable-gpu \ --mute-audio \ --no-default-browser-check \ --disable-software-rasterizer \ - --disable-features=site-per-process & + --disable-features=site-per-process \ + --disable-crash-reporter \ + --disable-extensions \ + --disable-sync & CHROME_PID=$! - wait $CHROME_PID 2>/dev/null || true + wait "$CHROME_PID" || CHROME_EXIT=$? + CHROME_EXIT=${CHROME_EXIT:-0} + + if [ "$STOPPING" -eq 1 ]; then + break + fi + + now="$(date +%s)" + if [ $(( now - WINDOW_START )) -gt "$RESTART_WINDOW_SEC" ]; then + WINDOW_START="$now" + RESTART_COUNT=0 + fi + + RESTART_COUNT=$((RESTART_COUNT + 1)) + log "Chromium exited with code=${CHROME_EXIT}; restart ${RESTART_COUNT}/${MAX_RESTARTS} in current window" + + if [ "$RESTART_COUNT" -ge "$MAX_RESTARTS" ]; then + log "fatal: too many Chromium restarts in ${RESTART_WINDOW_SEC}s" + exit 1 + fi + + sleep "$RESTART_BACKOFF_SEC" + unset CHROME_EXIT + unset CHROME_PID +done - echo "Chromium завершен, рестарт через 2 секунды..." - sleep 2 -done \ No newline at end of file From 480dfcd36e1fbf19774c9a26d4fcd45380c6ba6a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=9A=D0=BE=D0=B1=D1=8B=D0=BB=D0=BA=D0=B5=D0=B2=D0=B8?= =?UTF-8?q?=D1=87=20=D0=A4=D1=91=D0=B4=D0=BE=D1=80?= Date: Thu, 2 Apr 2026 12:00:06 +0300 Subject: [PATCH 3/3] add healthcheck --- docker-compose.yml | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/docker-compose.yml b/docker-compose.yml index 79fa825f..e64e93bb 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -15,7 +15,8 @@ services: - ./workspace:/app/workspace:rw - ./config.example.yaml:/app/config.example.yaml:ro depends_on: - - browser + browser: + condition: service_healthy stdin_open: true tty: true restart: always @@ -50,6 +51,12 @@ services: volumes: - browser_profiles:/src/browser_data restart: always + healthcheck: + test: ["CMD-SHELL", "curl -fsS http://127.0.0.1:9222/json/version >/dev/null || exit 1"] + interval: 10s + timeout: 3s + retries: 12 + start_period: 20s tunnel: image: cloudflare/cloudflared:latest