Files
bob dc7c3f99ae Add cs.money worker stack with per-worker IPRoyal residential proxy
Brings up the pull-model scraper: the .NET C2 hands skin+wear jobs to Python nodriver workers that scrape cs.money and post results back, plus the supporting Core/EFCore data model, migrations, and docker-compose orchestration.

IPRoyal proxying lets workers scale horizontally with a distinct residential exit IP each: every worker process mints its own sticky session at startup, and an in-process forwarding proxy injects the gateway auth so Chromium talks only to an auth-free localhost endpoint (zero CDP). On a Cloudflare challenge a worker rotates to a fresh session/IP and re-warms. Verified end-to-end against live IPRoyal: distinct US residential exits per worker and IP rotation on demand.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-05-31 15:03:53 -05:00

2.5 KiB

Containerized startup (C2 + worker)

One command brings up the cs.money C2 (control plane) and a worker. Postgres runs independently on the host; the C2 connects to it and auto-applies EF migrations on boot.

docker-compose up --build

Prerequisites

  1. Host Postgres reachable from containers. The C2 connects via host.docker.internal. Postgres must (a) listen on the Docker-facing interface (listen_addresses = '*' in postgresql.conf) and (b) allow the container subnet in pg_hba.conf. The DB (skintracker) should already have the schema, but the C2 also runs Database.Migrate() at startup as a safety net.
  2. A real exit IP for the worker. A bare datacenter/container IP gets challenged hard by Cloudflare. Set PROXY to a residential exit (see below).

Configuration (env vars / a .env file next to docker-compose.yml)

Var Default Purpose
SKINTRACKER_CONN Host=host.docker.internal;Port=5432;Database=skintracker;Username=postgres C2 → Postgres connection string
WORKER_TOKEN dev-worker-token Shared secret; C2 and worker must match
PROXY (none) Worker proxy host:port (auth-free)
SOLVE_SECONDS 45 Time the worker waits for you to clear Cloudflare
MAX_PAGES_PER_JOB 20 Cap on offset pages per skin+wear job
LOAD_IMAGES (off) 1 re-enables image loading (debugging)

Scaling workers

docker-compose up --build --scale worker=3

Remove the worker ports: mapping first — multiple workers can't share host port 6080 for noVNC. (Each gets the display internally; expose per-worker only if you need to watch a specific one.)

Notes / known gaps

  • IPRoyal auth: PROXY is passed to Chromium as --proxy-server, which ignores user:pass. For credentialed IPRoyal either IP-whitelist the worker's egress IP, or add a small forwarding-proxy sidecar that injects the auth (the .NET LocalForwardingProxy does this for the CSFloat path; a worker-side equivalent is a follow-up).
  • Unattended Cloudflare: the worker leans on nodriver + a residential IP clearing CF automatically. When it can't, use the noVNC tab to solve it once; the warmed profile then carries the clearance.