chromedp code passes Cloudflare Turnstile locally but not Docker container
Author: romvaracCreated May 7, 2026Updated May 7, 2026
The same chromedp program, against the same Cloudflare-protected URL, works on my macOS host but fails consistently inside a
Docker container with the same Chromium binary version. The container never advances past the Cloudflare interstitial — the page title
stays "Just a moment..." for the entire 60-second wait, then the script gives up.
#### Source
```go
// main.go
package main
import (
"context"
"fmt"
"os"
"strings"
"time"
"github.com/chromedp/chromedp"
)
func main() {
opts := append(chromedp.DefaultExecAllocatorOptions[:],
chromedp.Flag("headless", false),
chromedp.Flag("no-sandbox", true),
chromedp.Flag("disable-dev-shm-usage", true),
chromedp.Flag("disable-blink-features", "AutomationControlled"),
)
if path := os.Getenv("CHROME_PATH"); path != "" {
opts = append(opts, chromedp.ExecPath(path))
}
allocCtx, cancel := chromedp.NewExecAllocator(context.Background(), opts...)
defer cancel()
ctx, cancel := chromedp.NewContext(allocCtx)
defer cancel()
if err := chromedp.Run(ctx, chromedp.Navigate("https://community.cloudflare.com")); err != nil {
fmt.Fprintln(os.Stderr, "navigate:", err)
os.Exit(1)
}
deadline := time.Now().Add(60 * time.Second)
start := time.Now()
for time.Now().Before(deadline) {
var title string
_ = chromedp.Run(ctx, chromedp.Title(&title))
fmt.Printf("[%6.1fs] title=%q\n", time.Since(start).Seconds(), title)
if title != "" && !strings.Contains(strings.ToLower(title), "just a moment") {
fmt.Println("OK: cleared")
return
}
time.Sleep(500 * time.Millisecond)
}
fmt.Println("FAIL: blocked by Cloudflare (title never changed)")
os.Exit(1)
}Local (macOS) — works
$ go run .
[ 0.0s] title=""
[ 0.5s] title="Just a moment..."
[ 1.0s] title="Just a moment..."
[ 1.5s] title="Just a moment..."
[ 2.0s] title="Just a moment..."
[ 2.5s] title="Just a moment..."
[ 3.0s] title="Just a moment..."
[ 3.5s] title="Just a moment..."
[ 4.0s] title="Just a moment..."
[ 4.5s] title="Cloudflare Community"
OK: cleared Container — fails
Dockerfile:
# ---------- Builder ----------
FROM golang:1.26-bookworm AS builder
WORKDIR /src
COPY go.mod go.sum ./
RUN go mod download
COPY *.go ./
RUN CGO_ENABLED=0 GOOS=linux go build -trimpath -ldflags="-s -w" -o /out/crawler .
# ---------- Runtime ----------
FROM debian:bookworm-slim
RUN apt-get update && apt-get install -y --no-install-recommends \
ca-certificates \
chromium \
chromium-driver \
xvfb \
dumb-init \
&& rm -rf /var/lib/apt/lists/*
ENV DISPLAY=:99 \
CHROME_PATH=/usr/bin/chromium
WORKDIR /app
COPY --from=builder /out/crawler /app/crawler
ENTRYPOINT ["dumb-init", "--"]
CMD ["sh", "-c", "Xvfb :99 -screen 0 1280x1024x24 -nolisten tcp & exec /app/crawler"] $ docker build -t chromedp-repro . && docker run --rm chromedp-repro
[ 0.0s] title=""
[ 0.5s] title="Just a moment..."
[ 1.0s] title="Just a moment..."
[ 1.5s] title="Just a moment..."
... (120 polls, all "Just a moment...")
[ 60.0s] title="Just a moment..."
FAIL: blocked by Cloudflare (title never changed)Source: chromedp/chromedp