open-webui / Dockerfile
Murasame52's picture
Update Dockerfile
d5554fc verified
Raw
History Blame Contribute Delete
8.24 kB
# 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"]