Shipyard-neo如何绕过网站风控
前言
最近在捣鼓Astrbot,部署了Astrbot官方的shipyard-neo实现了让bot使用电脑。
不过在实际使用过程中,我发现官方的默认配置有两大问题
- 默认浏览器的ua明文headless
- 如果是服务器,ip也可能是idc的
以上两个问题导致bot在使用浏览器时有可能被风控,导致浏览器形同虚设,在实际使用时我发现bot使用浏览器访问Google search被风控。
通过修改官方的gull镜像(截至2026年6月20日),我成功地移除了headless chrome ua中的headless字样,同时通过部分配置给gull中的无头浏览器套上了干净的代理,通过这两个手段降低了ai agent无头浏览器被风控的概率。
以下是我实现用的编排和配置,有需要可以参考一下,希望可以帮到大家!
注意,其中shipyard-neo gull被我替换成了我的自定义镜像,以移除默认ua中的headless,如果官方后续有变动可以换成官方的service参考。
配置
docker compose
services:
# ── Gull Service (shared browser pool) ─────────────────
# Shared Chromium for all browser-python sandboxes. One Chromium
# process serves all sandboxes instead of per-sandbox Gull containers.
mihomo:
container_name: mihomo
image: metacubex/mihomo # 官方核心镜像
cap_add:
- NET_ADMIN # gvisor 需要修改容器内路由表
restart: unless-stopped
ports:
- "代理端口:代理端口" # HTTP/SOCKS5 混合代理端口
- "webui:webui"
volumes:
- /opt/work/mihomo/config:/root/.config/mihomo # 映射配置目录
devices:
- /dev/net/tun:/dev/net/tun
dns:
- 198.18.0.1
# dns_search: .
networks:
- bay-network
astrbot:
image: soulter/astrbot:latest
container_name: astrbot
restart: unless-stopped
ports:
- "${ASTRBOT_PORT:-6185}:6185"
volumes:
# AstrBot persistent data
- /opt/work/astrbot/data:/AstrBot/data
# Bay credentials auto-discovery (read-only)
- bay-data:/bay-data:ro
environment:
# Tell _discover_bay_credentials() where to find credentials.json
- BAY_DATA_DIR=/bay-data
depends_on:
bay:
condition: service_healthy
networks:
- bay-network
logging:
driver: json-file
options:
max-size: "50m"
max-file: "3"
gull-service:
# image: ghcr.io/astrbotdevs/shipyard-neo-gull:latest
image: nicocatxzc/shipyard-neo-gull:latest
container_name: bay-gull
restart: unless-stopped
environment:
- GULL_MODE=shared
- GULL_CDP_PORT=9222
- AGENT_BROWSER_IDLE_TIMEOUT_MS=600000 # 10 min session GC
- GULL_CHROMIUM_ARGS=--user-agent="Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/148.0.0.0 Safari/537.36" #custom user-agent
volumes:
- ./bay-cargos:/cargos:ro
# networks:
# - bay-network
network_mode: "container:mihomo"
depends_on:
- mihomo
bay:
image: ghcr.io/astrbotdevs/shipyard-neo-bay:latest
container_name: bay
restart: unless-stopped
ports:
- "8114:8114"
volumes:
# Docker socket — Bay creates sandbox containers dynamically
- /var/run/docker.sock:/var/run/docker.sock
# Config file
- /opt/work/astrbot/config.yaml:/app/config.yaml:ro
# SQLite database persistence
- bay-data:/app/data
# Cargo storage persistence (bind mount — shared with gull-service)
- ./bay-cargos:/var/lib/bay/cargos
environment:
- BAY_CONFIG_FILE=/app/config.yaml
- BAY_DATA_DIR=/app/data
# To inject a fixed API key instead of auto-generation:
# - BAY_API_KEY=sk-bay-your-key-here
networks:
- bay-network
healthcheck:
test: ["CMD", "curl", "-f", "http://localhost:8114/health"]
interval: 30s
timeout: 10s
retries: 5
start_period: 15s
logging:
driver: json-file
options:
max-size: "50m"
max-file: "5"
networks:
bay-network:
name: bay-network
driver: bridge
volumes:
bay-data:
name: bay-data
bay配置
server:
host: "0.0.0.0"
port: 8114
database:
# SQLite for single-instance deployment.
# For HA / multi-instance, switch to PostgreSQL:
# url: "postgresql+asyncpg://user:pass@db-host:5432/bay"
url: "sqlite+aiosqlite:///./data/bay.db"
echo: false
driver:
type: docker
# Pull latest images when creating new sandboxes.
# Production recommendation: "always" ensures you always get the latest image.
image_pull_policy: always
docker:
socket: "unix:///var/run/docker.sock"
# Bay in container, Ship/Gull in container — use container network direct connect
connect_mode: container_network
# Shared network name (must match docker-compose.yaml network)
network: "bay-network"
# Disable host port mapping — sandbox containers don't need to be reachable
# from outside the Docker network, reducing attack surface.
publish_ports: false
host_port: null
cargo:
root_path: "/var/lib/bay/cargos"
default_size_limit_mb: 1024
mount_path: "/workspace"
security:
# CHANGE-ME: 设置一个强随机密钥 (e.g. `openssl rand -hex 32`)
api_key: "openssl"
allow_anonymous: false
# ── Shared Browser Service ───────────────────────────────
# One Chromium process serves all browser-python sandboxes via gull-service.
# Set enabled: false to revert to per-sandbox Gull containers.
browser_service:
enabled: true
endpoint: "http://mihomo:8115"
# Container proxy environment injection.
# When enabled, Bay injects HTTP(S)_PROXY and NO_PROXY into sandbox containers.
proxy:
enabled: false
# http_proxy: "http://proxy.example.com:7890"
# https_proxy: "http://proxy.example.com:7890"
# Optional extra entries to append to default NO_PROXY list
# no_proxy: "my-internal.service"
# Warm Pool — pre-start standby sandbox instances to reduce cold-start latency.
# When a user creates a sandbox, Bay will first try to claim an available warm instance,
# delivering near-instant startup instead of waiting for container boot.
warm_pool:
enabled: true
warmup_queue_workers: 2 # Concurrent warmup workers
warmup_queue_max_size: 256 # Maximum queue depth
warmup_queue_drop_policy: "drop_newest"
warmup_queue_drop_alert_threshold: 50
interval_seconds: 30 # Pool maintenance scan interval
run_on_startup: true
profiles:
# ── Standard Python sandbox ────────────────────────
- id: python-default
description: "Standard Python sandbox with filesystem and shell access"
image: "ghcr.io/astrbotdevs/shipyard-neo-ship:latest"
runtime_type: ship
runtime_port: 8123
resources:
cpus: 1.0
memory: "1g"
capabilities:
- filesystem # includes upload/download
- shell
- python
idle_timeout: 1800 # 30 minutes
warm_pool_size: 0 # Keep 1 pre-warmed instance ready
# Environment variables injected into the runtime container (available in Python and Shell)
# Example: env: { TZ: "Asia/Shanghai", LANG: "en_US.UTF-8", CUSTOM_VAR: "value" }
env: {}
# Optional profile-level proxy override
# proxy:
# enabled: false
# ── Data Science sandbox (more resources) ──────────
- id: python-data
description: "Data science sandbox with extra CPU and memory"
image: "ghcr.io/astrbotdevs/shipyard-neo-ship:latest"
runtime_type: ship
runtime_port: 8123
resources:
cpus: 2.0
memory: "4g"
capabilities:
- filesystem # includes upload/download
- shell
- python
idle_timeout: 1800
warm_pool_size: 0
env: {}
# ── Browser + Python (shared browser pool) ──────────
- id: browser-python
description: "Browser automation with Python backend (shared Chromium)"
browser: shared # routes through gull-service, not per-sandbox gull
containers:
- name: ship
image: "ghcr.io/astrbotdevs/shipyard-neo-ship:latest"
runtime_type: ship
runtime_port: 8123
resources:
cpus: 2.0
memory: "2g"
capabilities:
- python
- shell
- filesystem
- browser
env: {}
idle_timeout: 1800
warm_pool_size: 1
gc:
# Enable automatic GC for production
enabled: true
run_on_startup: true
interval_seconds: 180 # 3 minutes
# Instance identifier — MUST be unique in multi-instance deployments
instance_id: "bay-prod"
idle_session:
enabled: true
expired_sandbox:
enabled: true
orphan_cargo:
enabled: true
orphan_container:
# Enable in production to clean up leaked containers.
# Safe as long as instance_id is unique per Bay instance.
enabled: true
mihomo配置
mode: rule
mixed-port: 7897
allow-lan: true # 允许内网调用
log-level: info
ipv6: false # ipv6
unified-delay: true
# 开启外部控制API
external-controller: 0.0.0.0:port # 访问端口
secret: "passwd" # 访问密码
# 允许面板跨域
external-controller-cors:
allow-origins:
- "*"
allow-private-network: true
profile:
store-selected: true
# tun配置
tun:
enable: true
stack: gvisor
auto-route: true
strict-route: false
auto-detect-interface: true
dns-hijack:
- any:53
# dns
dns:
enable: true
listen: :53
enhanced-mode: fake-ip
fake-ip-range: 198.18.0.1/16
fake-ip-filter:
- "*.lan"
- "*.local"
- "*.arpa"
- "+.msftncsi.com"
- "www.msftconnecttest.com"
# 默认dns
default-nameserver:
- 1.1.1.1
- 8.8.8.8
# 加密dns
nameserver:
- tls://1.1.1.1
- https://dns.google/dns-query
- tls://dns.adguard.com
# 防污染的 Fallback 走 DoH
fallback:
- https://cloudflare-dns.com/dns-query
- tls://8.8.8.8
fallback-filter:
geoip: true
geoip-code: CN
ipcidr:
- 240.0.0.0/4
- 0.0.0.0/32
# 节点列表
proxies:
- name: "节点"
proxy-groups:
- name: PROXY
type: select
proxies:
- "节点"
# 规则
rules:
#ipapi
- DOMAIN-KEYWORD,ip-api,PROXY
# === 1.核心风控 ===
- DOMAIN,accounts.google.com,PROXY
- DOMAIN,chat.openai.com,PROXY
- DOMAIN,auth0.openai.com,PROXY
- DOMAIN,challenges.cloudflare.com,PROXY
- DOMAIN-SUFFIX,google.com,PROXY
- DOMAIN-SUFFIX,gmail.com,PROXY
- DOMAIN-SUFFIX,openai.com,PROXY
- DOMAIN-KEYWORD,recaptcha,PROXY
- DOMAIN-KEYWORD,turnstile,PROXY
# === 社媒 ===
- DOMAIN-SUFFIX,facebook.com,PROXY
- DOMAIN-SUFFIX,instagram.com,PROXY
- DOMAIN-SUFFIX,twitter.com,PROXY
# === 内网 ===
- IP-CIDR,127.0.0.0/8,DIRECT
- IP-CIDR,10.0.0.0/8,DIRECT
- IP-CIDR,172.16.0.0/12,DIRECT
- IP-CIDR,192.168.0.0/16,DIRECT
- GEOIP,CN,DIRECT
- MATCH,DIRECT
