On `docker restart`, `/tmp` is preserved across container instances, so the
previous Xvfb's `/tmp/.X99-lock` survives into the new container. The new
Xvfb sees the existing lock and refuses to start, leaving the container
with no X server. Every Chrome launch then dies with "Missing X server or
$DISPLAY", and `cloakserve` returns 502 from `/json/version` forever.
Any orchestrator that restarts on unhealthy (the README-recommended
healthcheck + `restart: always`, autoheal sidecars, etc.) then enters a
permanent restart loop because every restart hits the same broken state.
This is silent for first-time users: the container appears to start
successfully (Xvfb did launch *once*), then degrades only after the first
restart. The fix is one line in the entrypoint: remove the stale lock
before starting Xvfb.
Fixes#283
Chromium's --proxy-server parser truncates passwords at '=' and other
special chars, causing SOCKS5 auth to silently fail and fall back to
direct connection. The dict path already encoded creds; now the string
path does too. Idempotent: pre-encoded input stays encoded.
CLI args like --fingerprint-locale were passed as raw passthrough args
to Chrome, missing the companion --lang flag that build_args() normally
adds. Caused Intl API to default to en-US while navigator.language
showed the correct locale — a detectable mismatch.
Fixes#130
Two ways to spoof WebRTC ICE candidate IPs:
1. --fingerprint-webrtc-ip=auto in args: resolves proxy exit IP via
HTTP call through the proxy (ipify.org). No extra deps needed.
2. geoip=True: auto-injects the flag for free (exit IP already
resolved during timezone/locale lookup, zero extra network cost).
Explicit IP (--fingerprint-webrtc-ip=1.2.3.4) also supported.
User-provided values always take precedence.
Python + JS wrappers, README docs, tests.
- Move `import websockets` to top-level (guaranteed by [serve] extra)
- Add --data-dir flag with smart default (Docker → /tmp/cloakserve, bare metal → ~/.cloakbrowser/cloakserve)
- Store launch params (tz/locale/proxy) on ChromeProcess for conflict logging
- Enhance GET / to return per-process detail (pid, port, seed, connections, config)
- Add connection refcounting in WS handlers for status visibility
- Add first-launch-wins note to README
- Add tests for data-dir, Docker detection, and connection tracking
Spawns a separate Chrome process per unique fingerprint seed, all behind
a single port (9222). Clients specify seeds and fingerprint params via
query string on the CDP URL:
connect_over_cdp("http://host:9222?fingerprint=12345&timezone=Asia/Tokyo")
Supports all --fingerprint-* flags as query params, geoip=true for
auto timezone/locale from proxy IP, and proxy= for per-process proxies.
- Rewrite bin/cloakserve from 57-line wrapper to aiohttp CDP multiplexer
- Add ChromePool with per-seed process management and port allocation
- Bidirectional WebSocket proxy for CDP traffic
- URL rewriting for /json/version, /json/list, and WS paths
- Rename _build_args -> build_args, _maybe_resolve_geoip -> maybe_resolve_geoip
- Add aiohttp + websockets to serve optional deps
- Dockerfile installs .[serve] extras
- Add 20 unit tests for cloakserve (param parsing, CLI args, URL rewriting)
Add bin/cloakserve — launches stealth Chromium with remote debugging
enabled so users can connect via connect_over_cdp() from the host.
Uses socat to forward 0.0.0.0:9222 to Chrome's localhost-only CDP port.
Usage: docker run -d -p 127.0.0.1:9222:9222 cloakhq/cloakbrowser cloakserve
Tested: all stealth checks pass via CDP, bot.sannysoft.com 54/54,
reCAPTCHA 0.9, zero detection regressions.
Add cloakhq/cloakbrowser Docker Hub image with Node.js, JS wrapper,
Xvfb headed mode, and cloaktest shortcut. Add launch feedback and IP
display to all examples. Update README Docker section for Docker Hub.