Zum Inhalt springen

Deployment — Docker & CDP-Endpunkt

Betreiben Sie Clearcote als dauerhaften CDP-Endpunkt und richten Sie jedes vorhandene Framework darauf — Playwright, Puppeteer, browser-use, Crawl4AI, Stagehand —, ohne Code zu ändern. Das Binary wird direkt gestartet (ohne --enable-automation), daher bleibt navigator.webdriver auf false: konstruktionsbedingt unauffällig.

Offizielles Docker-Image

Image ziehen und loslegen. Jeder CDP-Client verbindet sich über den freigegebenen Port.

bash
docker run -d --rm -p 127.0.0.1:9222:9222 -e CC_FINGERPRINT=user-7423 teamflatearth/clearcote   # CDP on http://localhost:9222

Damit läuft Chrome ohne seine Sandbox, wie in jedem Image vor sdk-0.41.0. Fügen Sie das seccomp-Profil des Images hinzu, und Chrome läuft mit seiner Sandbox; siehe die Sandbox von Chrome weiter unten.

python
from playwright.sync_api import sync_playwright

with sync_playwright() as p:
    browser = p.chromium.connect_over_cdp("http://localhost:9222")   # your code, unchanged
    page = browser.contexts[0].new_page()                            # the container's own profile
    page.goto("https://example.com")
    print(page.title())

Das Image enthält fest eingebaut den per SHA-256 verifizierten offenen Build für Linux, die metrikkompatiblen Nachbauten der Windows-Schriften (damit lateinischer Text dieselben Maße hat wie mit den Schriften der Persona) und ab sdk-0.41.0 Schriften für die übrigen Schriftsysteme, die ein Windows-Rechner von Haus aus darstellt (siehe Schriften), und nutzt standardmäßig eine kohärente native Linux-Persona. Der Browser läuft im Headed-Modus auf einem virtuellen Display (CC_HEADLESS=1 für reinen Headless-Betrieb). Ohne GPU im Container rendert WebGL in Software, und zwar über das Backend, dessen Limits zu der von der Persona angegebenen GPU passen: Mesa für eine Linux-Persona, im Headed- wie im Headless-Modus, und SwiftShader für eine Windows-Persona. Konfigurieren lässt sich das Image vollständig über Umgebungsvariablen:

bash
docker run -d -p 127.0.0.1:9222:9222 -e CC_PLATFORM=linux -e CC_FINGERPRINT=user-7423 -e CC_ACCEPT_LANGUAGE=en-US -e CC_TIMEZONE=America/New_York teamflatearth/clearcote
VariableBedeutung
CC_FINGERPRINTSeed → stabile Identität. Ohne diese Variable erhält jeder Container einen eigenen zufälligen Seed, der beim Start ausgegeben und über Neustarts hinweg im Profil des Containers gespeichert wird (Images vor sdk-0.39.0 gaben allen Containern denselben Seed). Setzen Sie die Variable, um eine Identität gezielt zu wählen oder wiederzuverwenden.
CC_PLATFORMlinux (Standard) | windows | macos | android. Eine Windows-Persona schaltet außerdem Widevine ein und auf dem lizenzierten Build (151 r15+) den HLSL-Shader-Dialekt (zum Überschreiben: CC_WIDEVINE / CC_SHADER_DIALECT).
CC_BRAND, CC_BRAND_VERSIONChrome (Standard) | Edge | Opera | Vivaldi sowie die Version, die diese Marke angibt.
CC_ACCEPT_LANGUAGE, CC_TIMEZONESprachliste und IANA-Zeitzone.
CC_TLS_PROFILENicht setzen: TLS folgt dann der Chrome-Version, die die Persona angibt. Pinnen Sie chrome-<major> nur zusammen mit einer passenden CC_BRAND_VERSION.
CC_HARDWARE_CONCURRENCY, CC_GPU_VENDOR, CC_GPU_RENDERER, CC_STORAGE_QUOTAEinzelne Persona-Werte.
CC_HEADLESS, CC_SCREEN1 für reinen Headless-Betrieb; die Größe des virtuellen Bildschirms (Standard 1920x1080x24).
CC_EXTRA_ARGSZusätzliche Browser-Switches, durch Leerzeichen getrennt. --disable-runtime-suppression entspricht hier stock_runtime des SDK (bleibt nur auf einer Engine erhalten, die den Switch kennt); --no-sandbox schaltet die Sandbox von Chrome ab.
CLEARCOTE_LICENSE_KEY, CC_VERSIONStartet den lizenzierten Build — siehe unten.
CC_IDLE_EXIT_SECONDSStoppt, sobald so viele Sekunden lang kein CDP-Client verbunden war, gezählt ab der ersten Antwort des Browsers (Standard: nie). Kombinieren Sie das mit --rm, damit ein verwaister Container ebenfalls verschwindet. Images ab sdk-0.40.0.
CC_SECRETS_FILEEine JSON-Datei im Container mit CLEARCOTE_LICENSE_KEY und/oder CC_PROXY, die beim Start einmal gelesen und dann gelöscht wird — siehe Secrets aus docker inspect heraushalten. Images ab sdk-0.40.0.
CLEARCOTE_FONT_DIRSIhre eigenen Schriften, in den Container gemountet (zum Beispiel eine Kopie des Fonts-Ordners eines Windows-Rechners) — siehe Schriften. Images ab sdk-0.41.0.
CLEARCOTE_FALLBACK_FONT_DIRSSchriften, die nur für Zeichen verwendet werden, die sonst keine Schrift abdeckt. Das Image setzt die Variable auf seine eigenen Schriften für weitere Schriftsysteme (/usr/local/share/clearcote/fonts); lassen Sie sie stehen, es sei denn, Sie ersetzen diese Schriften.
CLEARCOTE_PERSONA_ENV0 belässt die Persona auf der Kommandozeile des Browsers. Standardmäßig erreicht die Persona auf einer Engine, die das unterstützt (lizenzierter Build ab r32), den Browser des Containers über seine Umgebung und taucht daher nicht in der Prozessliste des Hosts auf; die serve-state-Zeile meldet persona_env. Images ab sdk-0.41.0.
Geben Sie sich als das Betriebssystem aus, auf dem der Container läuft. Manches, was eine Seite auslesen kann, stammt vom Host-Betriebssystem unterhalb des Browsers, und keine Persona-Einstellung reicht bis dorthin. In diesem Linux-Image wird Text vom FreeType-Scaler von Linux skaliert, und die Schriften kommen aus fontconfig, ganz gleich, was CC_PLATFORM sagt. Gemessen auf diesem Image mit CC_PLATFORM=windows: Wird die Schriftgröße in Schritten von 0,01 px verändert, ändert sich die Textbreite bei 66 % der Schritte (echtes Chrome unter Windows: 99 %), und Segoe UI und Georgia gelten bei der Messung als installiert, lassen sich aber nicht per Name laden. Der Fingerprint-Test schlägt bei beidem an. Die Standard-Linux-Persona besteht. Echte Windows-Schriften, die mit CLEARCOTE_FONT_DIRS gemountet werden, beheben auf dem lizenzierten Build ab r32 die Namen (Schriften), nicht aber den Scaler, den keine Einstellung erreicht. Für eine Windows-Identität nutzen Sie den Windows-Build oder gehostete Browser, die auf Windows-Rechnern laufen. Dasselbe gilt für serve() und launch() auf einem Linux-Server. Details: Der Font-Stack unter dem User-Agent.

Lizenzierter Build in Docker — Schlüssel übergeben, Cache mounten

Das Image bringt den offenen Build fest eingebaut mit. Setzen Sie CLEARCOTE_LICENSE_KEY, und der Container bezieht stattdessen den lizenzierten Build — den neuesten oder, im Pro-Plan, einen bestimmten per CC_VERSION. Mit kostenlosen Schlüsseln läuft immer der neueste Build; eine gepinnte Version wird abgelehnt.

bash
docker run -d -p 127.0.0.1:9222:9222 -v clearcote-cache:/opt/xdg-cache -e CLEARCOTE_LICENSE_KEY=cc_lic_... teamflatearth/clearcote

# Pro only: pin a major, an exact build, or a revision
#   -e CC_VERSION=154        -e CC_VERSION=154.0.8037.57        -e CC_VERSION=r36

Mounten Sie immer das Cache-Volume. Ein lizenzierter Container lädt die Engine beim ersten Start herunter; ohne persistentes Volume tut das jeder Container erneut. Mit dem Volume starten spätere Container aus dem gecachten Build.

Das Startup-Log zeigt, welche Engine Sie bekommen haben — ein falsch konfigurierter Schlüssel fällt so sofort auf und nicht erst beim ersten blockierten Request:

text
[clearcote] engine: /opt/xdg-cache/clearcote/pro-154.0.8037.57-r36/browser/chrome (licensed)
[clearcote] licence lease acquired
Erfordert ein Image, das mit SDK 0.26.1 oder neuer gebaut wurde, und mit 0.30.0 oder neuer für einen kostenlosen Schlüssel von GitHub — der lizenzierte Browser erwartet, dass ein kostenloser Container seine Lizenz während der Laufzeit aktuell hält, und verweigert ein älteres Image. Ältere veröffentlichte Images ignorieren den Schlüssel und liefern stillschweigend den offenen Build aus — aktualisieren Sie mit docker pull teamflatearth/clearcote. Ein lizenzierter Lauf bezieht beim Start außerdem ein Concurrency-Lease, der Container braucht also ausgehenden Zugriff auf die Lizenz-API; schlägt das Lease fehl, beendet sich der Container unter Angabe des Grundes, statt eine Engine zu starten, die nicht laufen kann. Mit einem kostenlosen Schlüssel läuft über alle Ihre Container hinweg immer nur ein Browser gleichzeitig — siehe wie lizenzierte Browser gezählt werden.

Ab Image sdk-0.40.0 laden mehrere lizenzierte Container, die gleichzeitig mit demselben Cache-Volume starten, die Engine nur einmal herunter: Der erste holt sie, die anderen warten darauf.

Secrets aus docker inspect heraushalten

Jede -e-Variable ist Teil der Konfiguration des Containers. Wer also docker inspect darauf ausführen kann (oder docker compose config bzw. die meisten Container-Dashboards lesen kann), sieht CLEARCOTE_LICENSE_KEY und das Passwort in einer CC_PROXY-URL im Klartext. Ab Image sdk-0.40.0 können Sie beides stattdessen als Datei übergeben: eine JSON-Datei im Container, deren Pfad CC_SECRETS_FILE angibt und die der Container beim Start einmal liest und dann löscht. Die Datei muss dem Benutzer des Images gehören (uid 10001).

bash
printf '{"CLEARCOTE_LICENSE_KEY": "%s"}' "$CLEARCOTE_LICENSE_KEY" > clearcote-secrets.json
tar --owner=10001 --group=10001 --mode=600 -cf clearcote-secrets.tar clearcote-secrets.json
id=$(docker create -p 127.0.0.1:9222:9222 -e CC_SECRETS_FILE=/tmp/clearcote-secrets.json   -v clearcote-cache:/opt/xdg-cache teamflatearth/clearcote)
docker cp - "$id:/tmp" < clearcote-secrets.tar    # copy the file in before the container starts
docker start "$id"
rm clearcote-secrets.json clearcote-secrets.tar

So geht auch der macOS-Start der SDKs vor. Wer Zugriff auf den Docker-Daemon hat, kann die Dateien und den Speicher eines laufenden Containers trotzdem lesen; behandeln Sie Zugriff auf den Daemon daher wie Zugriff auf den Schlüssel.

Seit sdk-0.40.0 läuft im Image tini als Init-Prozess. Hilfsprozesse des Browsers, die sich im Container beenden (etwa aus Skripten, die Sie per docker exec ausführen und die eigene Browser starten), werden so aufgeräumt, statt sich anzusammeln. docker stop erreicht den Browser weiterhin und gibt den Lizenz-Slot frei.

Schriften

Der Browser sieht nur die Schriften, auf die das SDK ihn verweist: die im Release gebündelten Nachbauten der Windows-Schriften, danach die unten genannten Verzeichnisse. Sonst erreicht ihn nichts unter /usr/share/fonts, eine im Image installierte Schrift kann also nie die Breiten ändern, die eine Windows-Persona meldet. Ab Image sdk-0.41.0:

  • Schriften für weitere Schriftsysteme sind eingebaut. Farbige Emoji, Chinesisch, Japanisch und Koreanisch (WenQuanYi Zen Hei, IPA Gothic) sowie Noto-Schriften für Arabisch, Armenisch, Bengalisch, Cherokee, Devanagari, Äthiopisch, Georgisch, Gujarati, Gurmukhi, Kannada, Khmer, Laotisch, Malayalam, Myanmar, Singhalesisch, Tamil, Telugu, Thai, Tibetisch und weitere, in /usr/local/share/clearcote/fonts, das CLEARCOTE_FALLBACK_FONT_DIRS hinter dem Bundle aufführt. Sie werden nur für Zeichen verwendet, die das Bundle nicht darstellen kann; diese Zeichen werden also gerendert, statt als leere Kästchen zu erscheinen, im offenen wie im lizenzierten Build. Eine lateinische Familie kommt nicht hinzu.
  • Ihre eigenen Schriften. Mounten Sie ein Verzeichnis mit Schriften, typischerweise eine Kopie von C:\Windows\Fonts eines Windows-Rechners, und nennen Sie es in CLEARCOTE_FONT_DIRS. Es wird vor dem Bundle eingereiht. Auf dem lizenzierten Build ab r32 wird jede Familie, die es mitbringt, als sie selbst unter ihrem eigenen Namen gerendert, und Helvetica, Times, Courier und die generischen CSS-Familien folgen; ältere Engines behalten ihre Nachbauten und nutzen das Verzeichnis nur für Zeichen, die sonst keine Schrift abdeckt. Verwenden Sie nur Schriften, für die Sie eine Lizenz haben. Außerhalb von Docker ist dieselbe Einstellung fontDirs des SDK.
bash
docker run -d -p 127.0.0.1:9222:9222 -v /srv/windows-fonts:/fonts:ro -e CLEARCOTE_FONT_DIRS=/fonts \
  -e CC_PLATFORM=windows -v clearcote-cache:/opt/xdg-cache -e CLEARCOTE_LICENSE_KEY=cc_lic_... teamflatearth/clearcote
docker exec <container> clearcote info --quick   # which writing systems render, which families are genuine
Sicherheit: Wer den CDP-Endpunkt erreicht, hat volle Kontrolle über den Browser. Geben Sie ihn nur in vertrauenswürdigen Netzen frei — -p 127.0.0.1:9222:9222 hält ihn lokal auf dem Host. Das docker/ Dockerfile ist nachprüfbar — bauen und verifizieren Sie es selbst.

Die Sandbox von Chrome

Die Linux-Sandbox von Chrome führt jeden Renderer (den Prozess, der eine Seite parst und ausführt) in eigenen Namespaces unter einem seccomp-Filter aus, sodass eine Seite, die ihren Renderer kompromittiert, trotzdem auf ihn beschränkt bleibt. Mit --no-sandbox hat dieser Renderer alles, was der Benutzer des Containers hat: seine Dateien, sein Netzwerk und seine anderen Prozesse. Das Standard-seccomp-Profil von Docker verweigert die Aufrufe, die diese Namespaces anlegen, deshalb starteten Images vor sdk-0.41.0 Chrome immer mit --no-sandbox.

Ab Image sdk-0.41.0 prüft der Container zuerst: Er führt dieselben Aufrufe aus wie die Sandbox von Chrome und startet Chrome mit seiner Sandbox, wenn sie funktionieren. Starten Sie ihn mit dem seccomp-Profil, das das Image mitliefert – dem Standardprofil von Docker, ergänzt um die zwei Namespace-Aufrufe, die Chrome braucht:

bash
# copy the profile out of the image (--tmpfs keeps docker from first copying the engine into a volume)
docker run --rm --tmpfs /opt/xdg-cache --entrypoint cat teamflatearth/clearcote /etc/clearcote/seccomp.json > clearcote-seccomp.json
docker run -d -p 127.0.0.1:9222:9222 --security-opt seccomp=clearcote-seccomp.json teamflatearth/clearcote
yaml
# docker compose
services:
  clearcote:
    image: teamflatearth/clearcote
    ports: ["127.0.0.1:9222:9222"]
    security_opt: ["seccomp=./clearcote-seccomp.json"]
  • Das Log zeigt, wie es ausgegangen ist: [clearcote] sandbox: on (…) oder [clearcote] sandbox: OFF, Chrome runs with --no-sandbox: … mit dem Grund und der Anleitung zum Einschalten. Die serve-state-Zeile enthält "sandbox": true oder false. Ohne das Profil läuft der Container genau wie bisher.
  • Außerdem braucht es den eigenen Benutzer des Images (nicht --user 0), CAP_SYS_CHROOT (standardmäßig gewährt; fügen Sie nach --cap-drop ALL wieder --cap-add SYS_CHROOT hinzu), einen Host, der unprivilegierte User-Namespaces erlaubt, und einen amd64-Rechner. Fehlt etwas davon, fällt der Container auf --no-sandbox zurück und nennt den Grund.
  • Der Kompromiss: Mit dem Profil kann jeder Prozess im Container, nicht nur Chrome, einen User-Namespace mit eigenem Netzwerk-Namespace anlegen und erreicht damit Netzwerkcode des Kernels, den das Standardprofil von Docker außer Reichweite hält. Die Renderer von Chrome, in denen nicht vertrauenswürdige Seiten laufen, bleiben unter dem eigenen Filter von Chrome. Ohne die Sandbox hat ein kompromittierter Renderer alles, was der Benutzer des Containers hat; das Profil ist also trotzdem die bessere Wahl. Verwenden Sie stattdessen nicht --privileged, --cap-add SYS_ADMIN oder seccomp=unconfined: Diese schalten weit mehr vom Schutz des Containers ab.
  • CC_EXTRA_ARGS=--no-sandbox schaltet die Sandbox bewusst ab. --no-zygote, --disable-namespace-sandbox, --renderer-cmd-prefix= und die Canvas-Bridge (--canvas-bridge-url=) schalten sie ebenfalls ab, weil Chrome seine Sandbox hier mit ihnen nicht betreiben kann.
  • Der macOS-Start der SDKs übergibt das Profil selbst, auf einem Docker, der auf einer x86_64-CPU läuft. Auf Apple Silicon läuft das Image emuliert, und die Sandbox bleibt dort vorerst aus.

Dauerhafter CDP-Endpunkt aus dem SDK — serve()

Starten Sie das Binary selbst und erhalten Sie eine cdp_url, an die sich jeder Client anhängen kann. Derselbe unauffällige Direktstart wie beim Image, gesteuert aus Ihrem eigenen Prozess.

python
from clearcote import serve

srv = serve(fingerprint="seed-123", platform="windows")   # -> srv.cdp_url
# attach ANY CDP client:
#   playwright:  p.chromium.connect_over_cdp(srv.cdp_url)
#   puppeteer:   puppeteer.connect({ browserURL: srv.cdp_url, defaultViewport: null })
#   browser-use / Crawl4AI / Stagehand: point them at srv.cdp_url
srv.close()
javascript
import { serve } from "clearcote";
const srv = await serve({ fingerprint: "seed-123", platform: "windows" });
// srv.cdpUrl -> connectOverCDP / puppeteer.connect({ browserURL, defaultViewport: null })
await srv.close();

Im Headless-Modus bekommt der bereitgestellte Browser ein Display in realer Größe — das der Persona oder eines, das aus echten Desktops ausgewählt wird —, und sein Fenster wird an den Arbeitsbereich angepasst, bevor sich ein Client verbindet. So meldet jede Seite, jeder Tab und jedes Popup ein Fenster, das auf den Bildschirm passt (SDK 0.31+). Für ein kleineres Fenster übergeben Sie windowSize: { width, height } (window_size in Python, WindowSize in .NET); mit Ihrem eigenen --window-size in args übernehmen Sie selbst die Kontrolle.

Ein Endpunkt, viele Identitäten — clearcote serve

Aus der Shell (Python- und Node-Pakete, 0.29+) betreibt clearcote serve einen dauerhaften Endpunkt, der für jede Identität, die eine Verbindung anfordert, einen eigenen Browser startet — Seed, Proxy, Zeitzone und Sprache kommen aus der Verbindungs-URL. Derselbe Seed nutzt seinen bereits laufenden Browser wieder.

bash
clearcote serve --port 9222 --idle-timeout 300 --max-browsers 16

# then, from any Playwright client:
#   chromium.connect_over_cdp("http://127.0.0.1:9222?fingerprint=acct-1&platform=windows")
#   chromium.connect_over_cdp("http://127.0.0.1:9222?fingerprint=acct-2&proxy=socks5://user:pass@host:1080&geoip=true")
#   (a password-protected proxy needs the licensed build)

Standardmäßig bindet sich der Endpunkt an localhost und lehnt Requests ab, die eine Webseite auslösen könnte. Inaktive Identitäten werden nach --idle-timeout Sekunden geschlossen, --max-browsers begrenzt, wie viele gleichzeitig laufen (weitere Identitäten erhalten HTTP 429), --data-dir behält das Profil jeder Identität über Neustarts hinweg, und --allow-host / --allow-origin ermöglichen den Betrieb hinter einem Reverse-Proxy. Unter http://127.0.0.1:9222/ sehen Sie, was gerade läuft. Mit einem Schlüssel „Kostenlos mit GitHub“ läuft jeweils nur ein Browser. Das ältere Skript clearcote-serve --port 9222 --fingerprint seed-123 für eine einzelne Identität ist weiterhin im Python-Paket enthalten.

Direkt — der offene Build ohne SDK

Der offene Build auf der Releases-Seite ist ein gewöhnliches Chromium-Binary, das Sie selbst mit executable_path und Switches starten können. Der lizenzierte Build braucht das SDK, das sein Lizenz-Token verwaltet. Die zusätzlichen Argumente unten sind die wichtigsten Standardwerte, die das SDK für diesen Seed unter Windows hinzufügt (außerdem führt es Feature-Flags zusammen und schaltet hinter einem Proxy QUIC ab):

python
from playwright.sync_api import sync_playwright

with sync_playwright() as p:
    browser = p.chromium.launch(
        executable_path=r"C:\clearcote\chrome.exe",
        ignore_default_args=["--enable-automation", "--enable-unsafe-swiftshader"],
        args=[
            "--fingerprint=seed-123",
            "--fingerprint-platform=windows",
            "--fingerprint-brand=chrome",
            "--accept-lang=en-US,en",
            "--lang=en-US",
            "--timezone=America/New_York",
            "--webrtc-ip-handling-policy=disable_non_proxied_udp",
            "--ignore-gpu-blocklist",
        ],
    )
    browser.new_page().goto("https://example.com")

Eigenes Image bauen (SDK-gesteuert)

Clearcote liefert ein Linux-x64-Binary und läuft daher headless in einem Container. Das Image braucht die Laufzeitbibliotheken des Browsers, fontconfig und das SDK. Der Browser verwendet das Schriften-Bundle seines Releases statt der Systemschriften; Schriften, die Sie mit apt installieren, bleiben für ihn also unsichtbar, bis Sie sie aufführen: Verlinken Sie die Schriften für weitere Schriftsysteme in ein Verzeichnis und nennen Sie es in CLEARCOTE_FALLBACK_FONT_DIRS (SDK 0.41.0+), wie es das offizielle Image tut, oder Ihre eigenen Schriften in CLEARCOTE_FONT_DIRS (siehe Schriften). Führen Sie nie ganz /usr/share/fonts auf: Dessen lateinische Familien würden die Breiten einer Windows-Persona verändern. Unter Linux ist die Persona standardmäßig eine kohärente native Linux-Identität. Der Schutz vor WebRTC-Leaks ist standardmäßig aktiv; die Privacy-Sandbox-APIs bleiben an, wie in Google Chrome. Sind libegl1 und libgl1-mesa-dri installiert, rendert das SDK das WebGL einer Linux-Persona über Mesa auf EGL, mit den Limits und der Renderer-Form, die echte Linux-Rechner melden: headless ab SDK 0.39.0 und ab 0.42.0 auch headed, sodass beide Modi dieselbe WebGL-Oberfläche zeigen. Ohne diese Pakete fällt es auf SwiftShader zurück. Ein Headed-Start unter Xvfb ohne Fenstermanager bekommt sein Fenster vor der ersten Seite an den Bildschirm angepasst (SDK 0.42.0).

dockerfile
FROM node:22-slim
RUN apt-get update && apt-get install -y --no-install-recommends \
      xz-utils libnss3 libnspr4 libgbm1 libasound2 libatk1.0-0 libatk-bridge2.0-0 libcups2 libdrm2 \
      libxkbcommon0 libxcomposite1 libxdamage1 libxrandr2 libxfixes3 libxext6 libxrender1 \
      libpango-1.0-0 libcairo2 libx11-6 libxcb1 libexpat1 libdbus-1-3 ca-certificates libegl1 libgl1-mesa-dri \
      fontconfig fonts-noto-color-emoji fonts-ipafont-gothic fonts-wqy-zenhei \
 && F=/usr/local/share/clearcote/fonts && mkdir -p $F && cd /usr/share/fonts \
 && cp -l truetype/noto/NotoColorEmoji.ttf truetype/wqy/wqy-zenhei.ttc opentype/ipafont-gothic/ipag.ttf $F/ \
 && rm -rf /var/lib/apt/lists/*
# emoji + CJK, used only where the bundle has no glyph
ENV CLEARCOTE_FALLBACK_FONT_DIRS=/usr/local/share/clearcote/fonts
WORKDIR /app
RUN npm i clearcote
RUN node --input-type=module -e "import { download } from 'clearcote'; await download();"   # bake the binary in
COPY run.mjs .
CMD ["node", "run.mjs"]
run.mjs
import { launchPersistentContext } from "clearcote";
const ctx = await launchPersistentContext("/tmp/prof", {
  headless: true,
  fingerprint: "user-1",
  proxy: { server: "http://gateway:8080", username: "u", password: "p" },
  geoip: true,      // timezone + languages + WebRTC IP matched to the proxy exit
  humanize: true,   // trusted bezier input; navigator.webdriver stays false
  args: ["--no-sandbox"],
});
const page = ctx.pages()[0] ?? (await ctx.newPage());
await page.goto("https://example.com");
await ctx.close();
Starten Sie den Container mit --shm-size=1g, um Abstürze wegen /dev/shm auf aufwendigen Seiten zu vermeiden. In Python funktioniert es genauso (from clearcote import launch_persistent_context, Optionen in snake_case).

Was sich per CDP verbinden lässt

ClientVorgehen
Playwrightchromium.connect_over_cdp(url) / connectOverCDP(url)
Puppeteerpuppeteer.connect({ browserURL: url, defaultViewport: null })
browser-use · Crawl4AI · Stagehanddie CDP-/Endpoint-Einstellung auf die URL richten
Alles, was CDP sprichtdas rohe DevTools Protocol auf dem Port

Soll stattdessen ein KI-Agent den Browser steuern? Siehe den MCP-Server. Sie fragen sich, warum ein Direktstart unauffälliger ist? Siehe Wie Erkennung funktioniert.