playwright / Dockerfile
cv3inx's picture
Bundle turnstile-solver in the project (no external URL needed)
f26e640
Raw
History Blame Contribute Delete
5.15 kB
# All-in-one Dockerfile: Playwright API + bundled turnstile-solver.
# This is what HF Space builds (single container).
# For VPS, prefer `docker compose up` which uses solver/Dockerfile +
# this same file but with multi-service split (see docker-compose.yml).
FROM mcr.microsoft.com/playwright:v1.49.0-jammy
USER root
# --- Step 1: essential packages ---
RUN apt-get update \
&& apt-get install -y --no-install-recommends \
util-linux procps psmisc ca-certificates curl unzip wget gnupg \
python3 python3-pip python3-venv \
&& rm -rf /var/lib/apt/lists/*
# --- Step 2: fonts (best-effort) ---
RUN apt-get update && \
for pkg in fonts-liberation fonts-noto fonts-noto-color-emoji fonts-noto-cjk \
fonts-ipafont-gothic fonts-wqy-zenhei fonts-thai-tlwg \
fonts-dejavu-core; do \
apt-get install -y --no-install-recommends "$pkg" || echo "skip: $pkg"; \
done && \
rm -rf /var/lib/apt/lists/*
# --- Step 3: Xvfb + GTK/X11 deps for Camoufox (used by the solver) ---
RUN apt-get update && \
apt-get install -y --no-install-recommends \
xvfb x11-utils dbus-x11 dumb-init \
libgtk-3-0 libdbus-glib-1-2 libxt6 libasound2 \
libx11-xcb1 libxcomposite1 libxdamage1 libxfixes3 libxrandr2 \
libpango-1.0-0 libnss3 libatk1.0-0 libatk-bridge2.0-0 \
libcups2 libxkbcommon0 libgbm1 libglib2.0-0 libexpat1 \
|| echo "Xvfb/GTK stack partial — solver may degrade" && \
rm -rf /var/lib/apt/lists/*
# --- Step 4: Google Chrome stable (best-effort) ---
RUN set -eux; \
( \
wget -q -O - https://dl.google.com/linux/linux_signing_key.pub | gpg --dearmor -o /usr/share/keyrings/google-chrome.gpg && \
echo 'deb [signed-by=/usr/share/keyrings/google-chrome.gpg] https://dl.google.com/linux/chrome/deb/ stable main' > /etc/apt/sources.list.d/google-chrome.list && \
apt-get update && \
apt-get install -y --no-install-recommends google-chrome-stable \
) || echo "Google Chrome install failed — channel:'chrome' will be unavailable, chromium still works"; \
rm -rf /var/lib/apt/lists/*
ENV PORT=7860 \
SOLVER_PORT=9988 \
TIMEOUT_MS=1800000 \
HOME=/home/pwuser \
BUN_INSTALL=/home/pwuser/.bun \
PATH=/home/pwuser/.bun/bin:/usr/local/bin:/usr/bin:/bin \
PLAYWRIGHT_BROWSERS_PATH=/ms-playwright \
PLAYWRIGHT_SKIP_BROWSER_DOWNLOAD=1 \
NODE_PATH=/app/node_modules:/app/helpers \
TRANSFORMERS_CACHE=/app/.cache/transformers \
TESSDATA_PREFIX=/app/tesseract-data \
COOKIES_DIR=/app/cookies \
CAMOUFOX_HEADLESS=virtual \
PYTHONUNBUFFERED=1 \
TURNSTILE_SOLVER_URL=http://127.0.0.1:9988
WORKDIR /app
RUN mkdir -p /app/runs /app/helpers /app/public /app/cookies \
/app/.cache/transformers /app/tesseract-data \
/app/solver /home/pwuser \
&& chown -R 1000:1000 /app /home/pwuser
# --- Solver: install Python deps as root (needs system site-packages access) ---
COPY --chown=1000:1000 solver/requirements.txt /app/solver/requirements.txt
RUN pip3 install --no-cache-dir --break-system-packages \
-r /app/solver/requirements.txt \
&& python3 -m camoufox fetch \
|| echo "[warn] solver dep install partial — /solve may degrade"
USER 1000
# --- Bun for the Playwright API server ---
RUN curl -fsSL https://bun.sh/install | bash
COPY --chown=1000:1000 package.json ./
RUN bun install --production --ignore-scripts
# --- Pre-fetch CAPTCHA models so first request is fast ---
RUN bun -e 'try { \
const { pipeline, env } = await import("@huggingface/transformers"); \
env.cacheDir = "/app/.cache/transformers"; \
console.log("[prefetch] whisper-tiny.en..."); \
await pipeline("automatic-speech-recognition", "Xenova/whisper-tiny.en", { quantized: true }); \
console.log("[prefetch] whisper done"); \
} catch (e) { console.warn("[prefetch] whisper skipped:", e.message); }' \
|| echo "whisper prefetch skipped"
RUN cd /app/tesseract-data && \
(curl -fsSLO https://github.com/tesseract-ocr/tessdata_fast/raw/main/eng.traineddata \
&& echo "[prefetch] tesseract eng.traineddata done") \
|| echo "tesseract prefetch skipped"
# --- Application code ---
COPY --chown=1000:1000 helpers/ ./helpers/
COPY --chown=1000:1000 public/ ./public/
COPY --chown=1000:1000 solver/solver.py solver/service.py solver/entrypoint.sh ./solver/
COPY --chown=1000:1000 solver/web ./solver/web
COPY --chown=1000:1000 server.js ./
COPY --chown=1000:1000 supervisor.sh ./
USER root
RUN chmod +x /app/solver/entrypoint.sh /app/supervisor.sh \
&& chown -R 1000:1000 /app
USER 1000
# --- Sanity check ---
RUN test -f /app/server.js \
&& test -f /app/supervisor.sh \
&& test -f /app/solver/service.py \
&& test -f /app/public/index.html \
&& test -d /app/helpers/stealth \
&& test -d /app/helpers/captcha \
&& test -f /app/node_modules/playwright/package.json \
&& echo "build artifacts OK"
EXPOSE 7860
# Supervisor launches the solver in the background, then the API in the
# foreground. If either dies the whole container exits and HF/Docker
# restarts it.
CMD ["bash", "/app/supervisor.sh"]