Spaces:
Paused
Paused
File size: 8,241 Bytes
b084584 6607fbf 9ee535c 6607fbf 9ee535c 6607fbf ada1307 74b5f90 d5554fc 6607fbf 9ee535c 6607fbf 9ee535c 6607fbf 9ee535c 6607fbf 9ee535c 6607fbf d5554fc 6607fbf 9ee535c 6607fbf c0d74eb 2ec39a0 b084584 6607fbf b084584 2ec39a0 b084584 2ec39a0 6607fbf 2ec39a0 b084584 2ec39a0 b084584 2ec39a0 6607fbf 2ec39a0 b084584 2ec39a0 b084584 9ee535c b084584 2ec39a0 ada1307 2ec39a0 b084584 9ee535c b084584 d5554fc 2ec39a0 d5554fc ada1307 9ee535c ada1307 9ee535c ada1307 9ee535c ada1307 9ee535c ada1307 9ee535c ada1307 9ee535c ada1307 2b6ef07 ada1307 2b6ef07 b084584 6607fbf d5554fc 6607fbf 2ec39a0 b084584 d5554fc 2ec39a0 ada1307 d5554fc b084584 2ec39a0 | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 | # syntax=docker/dockerfile:1
# Standalone Hybrid Turnstile Solver (Go + Rust + C++ + Python)
#
# HF Space 拉取方式:构建时 git clone 完整仓库(含 vendor/chromium 离线 deb)。
# Chromium:优先安装仓库内置 Gitee chromium-browser.deb,不依赖构建时访问 Gitee。
#
# REPO_URL 默认: https://github.com/xiaocongyu66/turnstile-solver.git
# REPO_REF 默认: main
# CHROMIUM_TAG 默认: 22.04_amd64 | 22.04_arm64
#
# Hardware: ≥ 2 vCPU / 16 GB RAM recommended
ARG PYTHON_VERSION=3.12-bookworm
ARG REPO_URL=https://github.com/xiaocongyu66/turnstile-solver.git
ARG REPO_REF=main
ARG CHROMIUM_TAG=
# ========== Stage 0: ALWAYS clone full GitHub source (includes vendor/chromium) ==========
FROM debian:bookworm-slim AS source
ARG REPO_URL
ARG REPO_REF
ENV DEBIAN_FRONTEND=noninteractive
RUN apt-get update && apt-get install -y --no-install-recommends \
git ca-certificates \
&& rm -rf /var/lib/apt/lists/*
WORKDIR /src
# Need full history depth only for files; large vendor/chromium is in the tree
RUN set -eu; \
echo "Cloning ${REPO_URL} @ ${REPO_REF} (full tree with vendor/chromium)"; \
git clone --depth 1 --branch "${REPO_REF}" "${REPO_URL}" /src/app \
|| git clone --depth 1 "${REPO_URL}" /src/app; \
cd /src/app && git checkout "${REPO_REF}" 2>/dev/null || true; \
test -f /src/app/watchdog/src/main.rs; \
test -f /src/app/gateway/main.go; \
test -f /src/app/worker/browser_worker.py; \
test -f /src/app/worker/proxy_pool.py; \
test -f /src/app/worker/proxy_relay.py; \
test -f /src/app/worker/cf_ares_helper.py; \
test -d /src/app/vendor/CF-Ares/cf_ares; \
test -f /src/app/util/solver_util.cpp; \
test -f /src/app/docker/entrypoint.sh; \
test -d /src/app/vendor/chromium; \
ls -la /src/app/vendor/chromium; \
echo "Source OK: $(cd /src/app && git rev-parse --short HEAD 2>/dev/null || echo unknown)"
# ---------- Go gateway ----------
FROM golang:1.22-bookworm AS gobuild
WORKDIR /src
COPY --from=source /src/app/gateway/go.mod /src/app/gateway/main.go ./
RUN mkdir -p /out && go build -trimpath -ldflags='-s -w' -o /out/solver-gateway .
# ---------- Rust watchdog ----------
FROM rust:1-bookworm AS rustbuild
WORKDIR /src
RUN mkdir -p /out
COPY --from=source /src/app/watchdog/Cargo.toml ./
COPY --from=source /src/app/watchdog/Cargo.lock* ./
COPY --from=source /src/app/watchdog/src ./src
RUN cargo build --release && cp target/release/solver-watchdog /out/solver-watchdog
# ---------- C++ util ----------
FROM debian:bookworm-slim AS cppbuild
RUN apt-get update && apt-get install -y --no-install-recommends g++ \
&& rm -rf /var/lib/apt/lists/* && mkdir -p /out
COPY --from=source /src/app/util/solver_util.cpp /src/app/util/solver_util.hpp /src/
RUN g++ -O2 -std=c++17 -o /out/solver-util /src/solver_util.cpp
# ---------- Runtime ----------
FROM python:${PYTHON_VERSION}
ARG CHROMIUM_TAG
ENV DEBIAN_FRONTEND=noninteractive \
PYTHONDONTWRITEBYTECODE=1 \
PYTHONUNBUFFERED=1 \
PORT=7860 \
HOST=0.0.0.0 \
PROJECT_ROOT=/app \
SOLVER_PYTHON=python \
SOLVER_GATEWAY_WORKERS=auto \
SOLVER_GATEWAY_WORKERS_MAX=auto \
TURNSTILE_SOLVER_HEADLESS=1 \
PLAYWRIGHT_BROWSERS_PATH=/ms-playwright
RUN apt-get update && apt-get install -y --no-install-recommends \
tini ca-certificates curl \
libnss3 libnspr4 libatk1.0-0 libatk-bridge2.0-0 libcups2 libdrm2 \
libxkbcommon0 libxcomposite1 libxdamage1 libxfixes3 libxrandr2 \
libgbm1 libasound2 libpango-1.0-0 libcairo2 libatspi2.0-0 \
libx11-6 libx11-xcb1 libxcb1 libxext6 libxshmfence1 fonts-liberation \
unzip \
&& rm -rf /var/lib/apt/lists/* \
&& pip install --no-cache-dir \
'playwright>=1.55' \
'curl_cffi>=0.5.7' \
'requests>=2.28.0' \
'seleniumbase>=4.0.0' \
'undetected-chromedriver>=3.5.0' \
'selenium>=4.15.0' \
'cf-ares>=0.1.0' || pip install --no-cache-dir \
'playwright>=1.55' 'curl_cffi>=0.5.7' 'requests>=2.28.0' \
'seleniumbase>=4.0.0' 'undetected-chromedriver>=3.5.0' 'selenium>=4.15.0'
# Offline install: bundled debs from vendor/chromium (Gitee jizijhj/chromium_1)
COPY --from=source /src/app/vendor/chromium /opt/vendor/chromium
RUN set -eux; \
arch="$(dpkg --print-architecture)"; \
tag="${CHROMIUM_TAG}"; \
if [ -z "$tag" ]; then \
case "$arch" in \
amd64) tag="22.04_amd64" ;; \
arm64) tag="22.04_arm64" ;; \
*) tag="22.04_amd64" ;; \
esac; \
fi; \
dir="/opt/vendor/chromium/${tag}"; \
echo "Installing offline chromium from ${dir}"; \
if [ ! -d "$dir" ]; then \
echo "WARN: missing ${dir}, trying any matching *_${arch}"; \
dir="$(ls -d /opt/vendor/chromium/*_${arch} 2>/dev/null | head -1 || true)"; \
fi; \
if [ -n "$dir" ] && [ -f "${dir}/chromium-browser.deb" ]; then \
cd "$dir"; \
dpkg -i chromium-codecs-ffmpeg-extra.deb 2>/dev/null || true; \
dpkg -i chromium-browser.deb || true; \
dpkg -i chromium-browser-l10n.deb 2>/dev/null || true; \
apt-get update && apt-get install -y -f --no-install-recommends || true; \
rm -rf /var/lib/apt/lists/*; \
else \
echo "WARN: no bundled chromium deb for arch=${arch}"; \
fi; \
CHROME=""; \
for c in \
/usr/bin/chromium-browser \
/usr/bin/chromium \
/usr/lib/chromium-browser/chromium-browser \
/usr/lib/chromium/chromium \
/usr/local/bin/chromium-browser; do \
if [ -x "$c" ]; then CHROME="$c"; break; fi; \
done; \
if [ -n "$CHROME" ]; then \
echo "Installed system chromium (fallback): $CHROME"; \
"$CHROME" --version || true; \
ln -sf "$CHROME" /usr/local/bin/chromium-browser; \
echo "$CHROME" > /etc/solver-chrome-path; \
else \
echo "WARN: system chromium missing"; \
fi; \
# Always install modern Playwright Chromium — Turnstile rejects ancient 108-era
# chromium-browser debs. Worker prefers /ms-playwright over system chrome.
echo "Installing Playwright bundled chromium → /ms-playwright"; \
mkdir -p /ms-playwright; \
PLAYWRIGHT_BROWSERS_PATH=/ms-playwright python -m playwright install --with-deps chromium || \
PLAYWRIGHT_BROWSERS_PATH=/ms-playwright python -m playwright install chromium; \
find /ms-playwright -type f \( -name chrome -o -name chromium -o -name headless_shell \) 2>/dev/null | head -20
WORKDIR /app
COPY --from=source /src/app/worker /app/worker
COPY --from=source /src/app/vendor/CF-Ares /app/vendor/CF-Ares
# also ship under worker/ so helper finds it even if CF_ARES_PATH is wrong
COPY --from=source /src/app/vendor/CF-Ares /app/worker/vendor/CF-Ares
COPY --from=source /src/app/docker/entrypoint.sh /entrypoint.sh
COPY --from=gobuild /out/solver-gateway /app/gateway/solver-gateway
COPY --from=rustbuild /out/solver-watchdog /app/watchdog/solver-watchdog
COPY --from=cppbuild /out/solver-util /app/util/solver-util
ENV PYTHONPATH=/app/worker:/app/vendor/CF-Ares \
CF_ARES_PATH=/app/vendor/CF-Ares \
PROXY_RELAY_WORK_DIR=/tmp/solver-proxy-relay \
PROXY_RELAY_ENABLED=1 \
PROXY_RELAY_AUTO_INSTALL=1 \
CF_ARES=1 \
CF_ARES_BROWSER_ENGINE=undetected \
CF_ARES_HEADLESS=1 \
CF_ARES_TIMEOUT=60 \
CF_ARES_SESSION_DIR=/tmp/solver-cf-ares-sessions
RUN chmod +x /entrypoint.sh /app/gateway/solver-gateway \
/app/watchdog/solver-watchdog /app/util/solver-util \
/app/worker/browser_worker.py \
&& mkdir -p /app/logs /data/logs /tmp/solver-proxy-relay /tmp/solver-cf-ares-sessions \
&& (test -d /app/vendor/CF-Ares/cf_ares && echo "vendor CF-Ares OK" || echo "WARN: vendor CF-Ares missing — rely on pip cf-ares") \
&& (test -d /app/worker/vendor/CF-Ares/cf_ares && echo "worker vendor OK" || true) \
&& ls -la /app/vendor 2>/dev/null || true \
&& python -c "import sys; sys.path[:0]=['/app/vendor/CF-Ares','/app/worker']; import cf_ares; print('cf_ares', getattr(cf_ares,'__version__','?')); import cf_ares_helper as h; d=h.diagnose(); print('diagnose', d); assert h.available() or d.get('error'); print('helper available', h.available())"
EXPOSE 7860
ENTRYPOINT ["/usr/bin/tini", "--"]
CMD ["/entrypoint.sh"] |