# Rigel — no-KYC SOCKS5 Proxy Shop Self-hosted SOCKS5 proxy storefront. Sells access to datacenter / residential / mobile proxies. Bitcoin via BTCPay. **No KYC** — username + email + password + arithmetic captcha, nothing else. **Status: LIVE — end-to-end verified 2026-09-10.** Real BTC payment → NBXplorer match → BTCPay webhook → subscription activated → per-user SOCKS5 credentials issued → authenticated proxy access **proven from an external network** (off-LAN vantage, correct country exit). ## Stack | Piece | Detail | |---|---| | Storefront | Flask SPA — `/opt/rigel/app.py` (SQLite, no-KYC auth, BTCPay invoicing) | | Proxy frontend | `/opt/rigel/proxy_server.py` — authenticated SOCKS5 on `:1081` | | Container | **CT 158 `rigel` @ `10.30.20.116`** — Debian 12, nginx `:80` → Flask `:5000` | | Services | `rigel.service` (`:5000`), `rigel-proxy.service` (`:1081`) | | Payments | BTCPay (store id + keys in Teable → `API_Credentials`) — webhook → `POST /api/btcpay/webhook` | | Public web | `https://rigel.thetempleofdoom.com` (fleet tunnel `1aeb1ac0`, **remote-managed**) | | Public SOCKS5 | **`76.146.4.178:1081`** — WAN port-forward (see below) | > **No secrets in this repo.** Store IDs, API keys and webhook secrets live in the > `rigel.service` environment and in Teable → `API_Credentials`. ## Inventory | Location | Type | Endpoint | |---|---|---| | Tokyo | datacenter (Nord exit) | CT680 `10.30.20.154:1080` | | London | datacenter (Nord exit) | CT681 `10.30.20.71:1080` | | Sydney | datacenter (Nord exit) | CT682 `10.30.20.189:1080` | | Residential | rotating / sticky | IPRoyal `geo.iproyal.com:12321` | | Mobile 4G | rotating | IPRoyal `4g.iproyal.com` | `proxy_server.py` derives the upstream list from `app.py`'s `LOCATIONS` (single source of truth) so the shop and the proxy can never disagree about inventory. ## API | Route | Body | Purpose | |---|---|---| | `GET /api/captcha` | — | arithmetic challenge | | `POST /api/register` | `{username, email, password, captcha_id, captcha}` | no-KYC signup | | `POST /api/login` | `{username, password}` | session | | `POST /api/buy` | `{plan_id}` | creates BTCPay invoice + pending subscription | | `GET /api/subscriptions` | — | user's active proxies + issued credentials | | `POST /api/btcpay/webhook` | BTCPay payload | activates subscription + issues creds | Plans: `day` (8,000 sats) · `week` (45,000 sats) · `month` (150,000 sats). ## Public SOCKS5 access — the part that isn't obvious A Cloudflare tunnel **cannot** carry SOCKS5 (HTTP-only), and Tailscale Funnel's raw-TCP mode does not actually forward publicly (verified, then reverted). Customers therefore connect to the **home WAN IP directly**: the router DNATs `tcp 1081 → 10.30.20.116:1081`. ⚠️ **If SOCKS5 ever stops being reachable from the internet, check in this order:** 1. **Router** — `iptables -t nat -L VSERVER -n | grep 1081` 2. **Hook present?** — `/jffs/scripts/firewall-start` must exist and be executable (setting the `vts_rulelist` nvram var alone does **not** emit the DNAT on this firmware) 3. **Service** — `systemctl is-active rigel-proxy` inside CT158 4. **Never trust a LAN test** — NAT loopback can pass while the world can't reach it. Verify from an external host. ## Auth model `proxy_server.py` validates every SOCKS5 username/password against `rigel.db`: the subscription must exist, be **active**, and **not expired**. The subscription's location selects the upstream exit. Unknown user, wrong password, expired sub, or wrong auth method → rejected; no traffic leaves. All time comparisons are **UTC**. ### Raw upstream egress lock The Nord `:1080` exits are LAN-only "dumb relays" with no auth by design. To stop tailnet nodes (100.64/10), the VPN tunnel (tun0), and other LAN hosts from using them for free, each Nord CT (680/681/682) restricts `:1080` to the Rigel frontend (CT158, `.116`) + loopback. Rule lives in `/etc/network/if-up.d/rigel-egress-lock` (persists across reboot, same hook mechanism as the Nord killswitch). Re-apply or inspect with: ```sh sh /etc/network/if-up.d/rigel-egress-lock iptables -S INPUT | grep 1080 ``` ## Deploy ```sh tar czf rigel.tar.gz app.py proxy_server.py scp rigel.tar.gz root@10.30.20.85:/tmp/ ssh root@10.30.20.85 "pct push 158 /tmp/rigel.tar.gz /tmp/rigel.tar.gz && pct exec 158 -- bash -c ' cd /opt/rigel && cp app.py app.py.bak-\$(date +%s) && cp proxy_server.py proxy_server.py.bak-\$(date +%s) && tar xzf /tmp/rigel.tar.gz && systemctl restart rigel rigel-proxy'" ``` Always back up the running file before overwriting it. CT158 does **not** accept the standard fleet root password over SSH — deploy through the Proxmox host with `pct exec`. ## Gotchas - **Fleet tunnel is REMOTE-MANAGED** — edit ingress via the Cloudflare API, not the local `config-fleet.yml`. Local edits are silently ignored. - **`checkoutLink` comes back with the LAN host** (it's derived from the API call's Host header) — `app.py` rewrites the prefix onto `BTCPAY_PUBLIC_URL`. - **SOCKS5 CONNECT to a domain target must length-prefix the domain** (`atyp=3`). Omit the prefix and the upstream reads the first character as a length and hangs. - **`rigel.db` is gitignored** — never commit the live database. - BTCPay `NetworkFeeMode = Always` makes the exact amount land a few sats short (`PaidPartial` rather than `Settled`); activation still fires. Not settable via the Greenfield API.