File size: 5,147 Bytes
f26e640
 
 
 
 
69f12cd
 
 
 
f26e640
0c3bfb5
 
 
f26e640
e84ef16
 
f26e640
e84ef16
 
f26e640
 
e84ef16
 
 
 
f26e640
e84ef16
f26e640
 
 
 
 
 
 
e84ef16
 
f26e640
e84ef16
 
 
 
 
 
 
 
 
69f12cd
f26e640
69f12cd
a9d5f67
 
 
69f12cd
0c3bfb5
a920dd4
 
 
f26e640
 
 
 
69f12cd
 
a920dd4
f26e640
 
a9d5f67
69f12cd
f26e640
 
 
 
 
 
 
a9d5f67
69f12cd
f26e640
69f12cd
 
a9d5f67
69f12cd
 
f26e640
a920dd4
 
 
 
 
 
 
 
 
 
 
 
 
 
f26e640
0c3bfb5
dc59771
f26e640
 
a9d5f67
f26e640
 
 
 
 
 
69f12cd
f26e640
e84ef16
f26e640
 
e84ef16
 
a920dd4
e84ef16
 
 
69f12cd
 
f26e640
 
 
 
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
# 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"]