From a79d6b1906e80c4f27d9c251ddd0ff6dd3b34441 Mon Sep 17 00:00:00 2001 From: justin Date: Fri, 5 Jun 2026 18:39:26 -0500 Subject: [PATCH] feat(healthcare): add gost proxy-relay so Chromium can use the residential proxy Chromium rejects authenticated SOCKS5 ('Browser does not support socks5 proxy authentication'). Add a gost (ginuerzh/gost:2.11.5) 'proxy-relay' sidecar that listens unauthenticated on socks5://proxy-relay:11080 and forwards to the authenticated residential upstream (HEALTHCARE_PROXY_UPSTREAM_URL). Workers point Playwright at the relay via HEALTHCARE_PROXY_URL=socks5://proxy-relay:11080. env template: split into HEALTHCARE_PROXY_UPSTREAM_URL (authenticated, password percent-encoded so '#' -> %23) and HEALTHCARE_PROXY_URL (the relay address). Validated end-to-end on dev: workers Chromium -> proxy-relay -> residential egress IP 76.228.206.147; NPPES + PECOS both HTTP 200. --- docker-compose.yml | 26 +++++++++++++++++--- infra/ansible/roles/app/templates/app.env.j2 | 21 ++++++++++------ 2 files changed, 36 insertions(+), 11 deletions(-) diff --git a/docker-compose.yml b/docker-compose.yml index 655cb0e..bd9d597 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -1,4 +1,20 @@ services: + # ── Residential proxy relay (healthcare NPPES/PECOS automation) ────── + # Chromium cannot use an *authenticated* SOCKS5 proxy directly, so we run a + # local unauthenticated gost relay that forwards to the authenticated + # residential upstream (username "performancewest"). The workers point + # Playwright at this relay via HEALTHCARE_PROXY_URL=socks5://proxy-relay:11080. + # + # HEALTHCARE_PROXY_UPSTREAM_URL is the authenticated upstream and is set in + # .env (rendered from the ansible vault). The password may contain URL + # special chars (e.g. '#'); store it percent-encoded ('%23') in that var. + proxy-relay: + image: ginuerzh/gost:2.11.5 + command: >- + -L socks5://:11080 + -F ${HEALTHCARE_PROXY_UPSTREAM_URL} + restart: unless-stopped + # ── Core Application ──────────────────────────────────────────────── site: build: ./site @@ -107,10 +123,11 @@ services: - CRYPTO_SWEEP_ADMIN_EMAIL=${ADMIN_EMAIL:-ops@performancewest.net} - USAC_USERNAME=${USAC_USERNAME} - USAC_PASSWORD=${USAC_PASSWORD} - # Residential SOCKS proxy for healthcare (NPPES/PECOS) Playwright flows. - # Username "performancewest"; full URL set in .env via the ansible vault. - - HEALTHCARE_PROXY_URL=${HEALTHCARE_PROXY_URL:-} - - UNDETECTED_PROXY_URL=${UNDETECTED_PROXY_URL:-} + # Healthcare (NPPES/PECOS) Playwright flows egress through the residential + # proxy via the unauthenticated gost relay sidecar (Chromium can't do + # authenticated SOCKS5). proxy-relay forwards to the authenticated upstream. + - HEALTHCARE_PROXY_URL=${HEALTHCARE_PROXY_URL:-socks5://proxy-relay:11080} + - UNDETECTED_PROXY_URL=${UNDETECTED_PROXY_URL:-socks5://proxy-relay:11080} - ANYTIME_MAILBOX_SIGNUP_EMAIL=${ANYTIME_MAILBOX_SIGNUP_EMAIL:-noreply@performancewest.net} - ANYTIME_MAILBOX_SIGNUP_PHONE=${ANYTIME_MAILBOX_SIGNUP_PHONE} - ANYTIME_MAILBOX_DEFAULT_PASSWORD=${ANYTIME_MAILBOX_DEFAULT_PASSWORD} @@ -140,6 +157,7 @@ services: - /etc/postfix/pw-warmup-start:/etc/postfix/pw-warmup-start:ro depends_on: - api-postgres + - proxy-relay restart: unless-stopped # ── ERPNext CRM ───────────────────────────────────────────────────── diff --git a/infra/ansible/roles/app/templates/app.env.j2 b/infra/ansible/roles/app/templates/app.env.j2 index 5933eec..956b0db 100644 --- a/infra/ansible/roles/app/templates/app.env.j2 +++ b/infra/ansible/roles/app/templates/app.env.j2 @@ -121,13 +121,20 @@ HESTIA_PASS={{ vault_hestia_pass | default('') }} # ── Residential proxy (healthcare NPPES/PECOS automation) ──────────────────── # CMS healthcare portals (NPPES, PECOS, I&A) block datacenter IPs, so the -# Playwright healthcare flows route through a residential SOCKS proxy. -# Format: socks5://performancewest:@hg409y7ez04.sn.mynetname.net: -# (username is "performancewest"). Set the full URL in the ansible vault as -# vault_healthcare_proxy_url. Leave blank to run without a proxy. -# UNDETECTED_PROXY_URL is the generic fallback used by FCC/state flows. -HEALTHCARE_PROXY_URL={{ vault_healthcare_proxy_url | default('') }} -UNDETECTED_PROXY_URL={{ vault_undetected_proxy_url | default(vault_healthcare_proxy_url | default('')) }} +# Playwright healthcare flows egress through a residential SOCKS proxy +# (host hg409y7ez04.sn.mynetname.net, username "performancewest"). +# +# Chromium can't use an *authenticated* SOCKS5 proxy, so the docker-compose +# "proxy-relay" (gost) listens unauthenticated and forwards to the +# authenticated upstream below. Workers point Playwright at the relay. +# +# HEALTHCARE_PROXY_UPSTREAM_URL = authenticated upstream consumed by the relay. +# Password may contain URL-special chars; store it PERCENT-ENCODED here +# (e.g. '#' -> '%23'): socks5://performancewest:@host:11080 +# HEALTHCARE_PROXY_URL = address Playwright/workers use (the relay, no auth). +HEALTHCARE_PROXY_UPSTREAM_URL={{ vault_healthcare_proxy_upstream_url | default('') }} +HEALTHCARE_PROXY_URL={{ healthcare_proxy_url | default('socks5://proxy-relay:11080') }} +UNDETECTED_PROXY_URL={{ undetected_proxy_url | default('socks5://proxy-relay:11080') }} # ── Application URLs ────────────────────────────────────────────────────────── DOMAIN=https://{{ domain }}