From df7e4de7f90cade8fefffaa9c145d5663ab67a6c Mon Sep 17 00:00:00 2001 From: andreysk0304 Date: Tue, 28 Apr 2026 18:16:41 +0300 Subject: [PATCH 1/3] Add VPS deployment workflow --- .gitea/workflows/deploy.yml | 22 ++++++ docker-compose.vps.yml | 14 ++++ docker-compose.yml | 8 +-- docs/vps-deploy.md | 133 ++++++++++++++++++++++++++++++++++++ scripts/deploy_vps.sh | 65 ++++++++++++++++++ 5 files changed, 238 insertions(+), 4 deletions(-) create mode 100644 .gitea/workflows/deploy.yml create mode 100644 docker-compose.vps.yml create mode 100644 docs/vps-deploy.md create mode 100755 scripts/deploy_vps.sh diff --git a/.gitea/workflows/deploy.yml b/.gitea/workflows/deploy.yml new file mode 100644 index 00000000..691e4311 --- /dev/null +++ b/.gitea/workflows/deploy.yml @@ -0,0 +1,22 @@ +name: Deploy to BrowserUse VPS + +on: + push: + branches: + - feature/api-for-subagent + workflow_dispatch: + +jobs: + deploy: + runs-on: deploy-vps + env: + DEPLOY_DIR: /home/BrowserUse-vps/apps/BrowserUse_and_ComputerUse_skills + DEPLOY_BRANCH: feature/api-for-subagent + HEALTH_URL: http://127.0.0.1:8088/health + steps: + - name: Deploy Docker Compose stack + shell: bash + run: | + set -Eeuo pipefail + cd "$DEPLOY_DIR" + bash scripts/deploy_vps.sh diff --git a/docker-compose.vps.yml b/docker-compose.vps.yml new file mode 100644 index 00000000..7b396679 --- /dev/null +++ b/docker-compose.vps.yml @@ -0,0 +1,14 @@ +services: + browser-api: + networks: + - browser-net + - lambdalab_frontend + + browser-view-proxy: + networks: + - browser-net + - lambdalab_frontend + +networks: + lambdalab_frontend: + external: true diff --git a/docker-compose.yml b/docker-compose.yml index 14f0da92..20517ddf 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -12,8 +12,8 @@ services: - BROWSER_USE_RPC_HOST=0.0.0.0 - BROWSER_USE_RPC_PORT=8787 ports: - - "6080:6080" - - "9222:9222" + - "${BROWSER_NOVNC_PUBLISH:-6080:6080}" + - "${BROWSER_CDP_PUBLISH:-9222:9222}" networks: browser-net: aliases: @@ -54,7 +54,7 @@ services: browser: condition: service_healthy ports: - - "8088:8088" + - "${BROWSER_API_PUBLISH:-8088:8088}" volumes: - /var/run/docker.sock:/var/run/docker.sock healthcheck: @@ -80,7 +80,7 @@ services: browser: condition: service_healthy ports: - - "6081:8080" + - "${BROWSER_VIEW_PROXY_PUBLISH:-6081:8080}" restart: always networks: - browser-net diff --git a/docs/vps-deploy.md b/docs/vps-deploy.md new file mode 100644 index 00000000..e329a49a --- /dev/null +++ b/docs/vps-deploy.md @@ -0,0 +1,133 @@ +# BrowserUse VPS Deployment + +This project deploys to `BrowserUse-vps@lambda.coredump.ru` with a Gitea/Forgejo Actions runner installed on the VPS. + +The server already has a root-owned `/opt/lambdalab` stack with Caddy on ports `80/443`. Keep this browser service as a separate app under the deploy user home directory, then attach the public-facing containers to the existing `lambdalab_frontend` Docker network through `docker-compose.vps.yml`. + +## SSH Access + +Add the public SSH key to the VPS user: + +```sh +ssh BrowserUse-vps@lambda.coredump.ru +mkdir -p ~/.ssh +chmod 700 ~/.ssh +printf '%s\n' '' >> ~/.ssh/authorized_keys +chmod 600 ~/.ssh/authorized_keys +``` + +The fingerprint `SHA256:/XC5ifPX8j+uRyp0Yw2zAl5nteWc3YcHeVHfCG+rhP4` is not enough by itself. `authorized_keys` needs the full public key line that starts with `ssh-ed25519`. + +## Initial Server Checkout + +Run once on the VPS: + +```sh +mkdir -p ~/apps +cd ~/apps +git clone -b feature/api-for-subagent https://git.lambda.coredump.ru/APEX/BrowserUse_and_ComputerUse_skills.git +cd BrowserUse_and_ComputerUse_skills +``` + +Create a server-local `.env` file in the checkout. It is intentionally not committed: + +```sh +OPENAI_API_KEY=... +OPENAI_BASE_URL=... +MODEL_DEFAULT=qwen3.5-122b +BROWSER_VIEW_BASE_URL=https://browser-view.lambda.coredump.ru +BROWSER_API_PUBLISH=127.0.0.1:8088:8088 +BROWSER_VIEW_PROXY_PUBLISH=127.0.0.1:6081:8080 +BROWSER_NOVNC_PUBLISH=127.0.0.1:6080:6080 +BROWSER_CDP_PUBLISH=127.0.0.1:9222:9222 +``` + +Then run the first deploy manually: + +```sh +bash scripts/deploy_vps.sh +curl -fsS http://127.0.0.1:8088/health +``` + +The deploy script uses both Compose files by default: + +```sh +docker-compose.yml:docker-compose.vps.yml +``` + +`docker-compose.vps.yml` connects `browser-api` and `browser-view-proxy` to the existing external `lambdalab_frontend` network so Caddy can reach them by Docker DNS. + +## Domain Binding + +The active Caddy config is root-owned at: + +```sh +/opt/lambdalab/caddy/Caddyfile +``` + +Add these vhosts to that file from an admin/root account: + +```caddyfile +browser-api.lambda.coredump.ru { + reverse_proxy browser-use-api:8088 +} + +browser-view.lambda.coredump.ru { + reverse_proxy browser-use-view-proxy:8080 +} +``` + +Then reload the existing Caddy container from `/opt/lambdalab`: + +```sh +cd /opt/lambdalab +docker compose exec caddy caddy reload --config /etc/caddy/Caddyfile +``` + +DNS must point both subdomains to the VPS public IP `155.212.185.120`. At inspection time, `lambda.coredump.ru` resolved to that IP, while `browser-api.lambda.coredump.ru` and `browser-view.lambda.coredump.ru` did not resolve yet. + +## Gitea/Forgejo Runner + +Install `act_runner` as the `BrowserUse-vps` user and register it with the repository, organization, or instance runner token: + +```sh +mkdir -p ~/act_runner +cd ~/act_runner +./act_runner generate-config > config.yaml +./act_runner --config config.yaml register \ + --no-interactive \ + --instance https://git.lambda.coredump.ru \ + --token '' \ + --name BrowserUse-vps \ + --labels deploy-vps:host +``` + +Start it under the same user: + +```sh +cd ~/act_runner +nohup ./act_runner daemon --config config.yaml > act_runner.log 2>&1 & +``` + +Because this account has `sudo: no`, a system-wide service cannot be installed from this user. If an admin enables a user-level systemd service for this account, run the same daemon command from that service instead of `nohup`. + +## CI/CD Behavior + +The workflow lives at `.gitea/workflows/deploy.yml`. + +It runs on: + +- push to `feature/api-for-subagent` +- manual `workflow_dispatch` + +The job expects a runner label named `deploy-vps`, registered as `deploy-vps:host`. It enters: + +```sh +/home/BrowserUse-vps/apps/BrowserUse_and_ComputerUse_skills +``` + +Then it fetches `origin/feature/api-for-subagent`, resets the tracked checkout to that commit, runs Docker Compose, and verifies: + +```sh +curl -fsS http://127.0.0.1:8088/health +``` diff --git a/scripts/deploy_vps.sh b/scripts/deploy_vps.sh new file mode 100755 index 00000000..37b7dd22 --- /dev/null +++ b/scripts/deploy_vps.sh @@ -0,0 +1,65 @@ +#!/usr/bin/env bash +set -Eeuo pipefail + +DEPLOY_BRANCH="${DEPLOY_BRANCH:-feature/api-for-subagent}" +HEALTH_URL="${HEALTH_URL:-http://127.0.0.1:8088/health}" +COMPOSE_FILES="${COMPOSE_FILES:-docker-compose.yml:docker-compose.vps.yml}" + +log() { + printf '[deploy] %s\n' "$*" +} + +fail() { + printf '[deploy] fatal: %s\n' "$*" >&2 + exit 1 +} + +command -v git >/dev/null 2>&1 || fail "git is not installed" +command -v docker >/dev/null 2>&1 || fail "docker is not installed" +command -v curl >/dev/null 2>&1 || fail "curl is not installed" +docker compose version >/dev/null 2>&1 || fail "docker compose plugin is not available" + +[ -d .git ] || fail "current directory is not a git checkout" +[ -f docker-compose.yml ] || fail "docker-compose.yml not found in current directory" +[ -f .env ] || fail ".env is missing; create it on the VPS with OPENAI_API_KEY and related runtime settings" + +compose_args=() +IFS=':' read -r -a compose_files <<< "$COMPOSE_FILES" +for compose_file in "${compose_files[@]}"; do + if [ -f "$compose_file" ]; then + compose_args+=("-f" "$compose_file") + else + fail "compose file not found: ${compose_file}" + fi +done + +log "fetching origin/${DEPLOY_BRANCH}" +git fetch --prune origin "+refs/heads/${DEPLOY_BRANCH}:refs/remotes/origin/${DEPLOY_BRANCH}" + +log "checking out ${DEPLOY_BRANCH}" +git checkout -B "$DEPLOY_BRANCH" "origin/$DEPLOY_BRANCH" +git reset --hard "origin/$DEPLOY_BRANCH" + +log "building Docker Compose services" +docker compose "${compose_args[@]}" build + +log "starting Docker Compose stack" +docker compose "${compose_args[@]}" up -d --remove-orphans + +log "current service state" +docker compose "${compose_args[@]}" ps + +log "waiting for API health at ${HEALTH_URL}" +for attempt in {1..30}; do + if curl -fsS "$HEALTH_URL" >/dev/null; then + log "API is healthy" + exit 0 + fi + + log "health check failed, retry ${attempt}/30" + sleep 2 +done + +log "API did not become healthy; browser-api logs follow" +docker compose "${compose_args[@]}" logs --tail=120 browser-api || true +fail "health check failed: ${HEALTH_URL}" From 5419746b3de693366d3e2a64e1e791ac2610ba4e Mon Sep 17 00:00:00 2001 From: andreysk0304 Date: Tue, 28 Apr 2026 18:23:11 +0300 Subject: [PATCH 2/3] Fix browser view nginx regex locations --- browser_env/nginx.browser-view.conf | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/browser_env/nginx.browser-view.conf b/browser_env/nginx.browser-view.conf index 3796234a..6d2ff069 100644 --- a/browser_env/nginx.browser-view.conf +++ b/browser_env/nginx.browser-view.conf @@ -28,11 +28,11 @@ http { proxy_pass http://browser:6080; } - location ~ ^/view/(?[a-f0-9]{16})$ { + location ~ "^/view/(?[a-f0-9]{16})$" { return 302 /view/$owner/vnc.html?path=view/$owner/websockify; } - location ~ ^/view/(?[a-f0-9]{16})/(?.*)$ { + location ~ "^/view/(?[a-f0-9]{16})/(?.*)$" { proxy_http_version 1.1; proxy_set_header Host $host; proxy_set_header Upgrade $http_upgrade; From c3bbd925b0dc17486396e8b3adde42d0a862aab7 Mon Sep 17 00:00:00 2001 From: andreysk0304 Date: Tue, 28 Apr 2026 18:38:19 +0300 Subject: [PATCH 3/3] Trigger VPS deployment workflow