README: document public SOCKS5 endpoint + router DNAT dependency, auth model, deploy; drop key material from a public repo
This commit is contained in:
97
README.md
97
README.md
@@ -1,15 +1,30 @@
|
|||||||
# Rigel — no-KYC SOCKS5 Proxy Shop
|
# Rigel — no-KYC SOCKS5 Proxy Shop
|
||||||
|
|
||||||
Self-hosted SOCKS5 proxy storefront. Sells access to residential/mobile/datacenter proxies. Bitcoin via BTCPay. No KYC — username + email + password + arithmetic captcha.
|
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
|
## Stack
|
||||||
- **App**: Flask single-page app, `/opt/rigel/app.py` (SQLite, no-KYC auth)
|
|
||||||
- **CT**: 158 `rigel` @ `10.30.20.116`, Debian 12, nginx :80 → Flask :5000
|
| Piece | Detail |
|
||||||
- **Service**: `rigel.service` (systemd)
|
|---|---|
|
||||||
- **Payments**: BTCPay store `[redacted]` / key `[redacted]` (webhook → `/api/btcpay/webhook`)
|
| Storefront | Flask SPA — `/opt/rigel/app.py` (SQLite, no-KYC auth, BTCPay invoicing) |
|
||||||
- **Public**: `https://rigel.thetempleofdoom.com` (fleet tunnel `1aeb1ac0`, REMOTE-MANAGED config via CF API)
|
| 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 `3j9HygtT…` — 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
|
## Inventory
|
||||||
|
|
||||||
| Location | Type | Endpoint |
|
| Location | Type | Endpoint |
|
||||||
|---|---|---|
|
|---|---|---|
|
||||||
| Tokyo | datacenter (Nord exit) | CT680 `10.30.20.154:1080` |
|
| Tokyo | datacenter (Nord exit) | CT680 `10.30.20.154:1080` |
|
||||||
@@ -18,21 +33,69 @@ Self-hosted SOCKS5 proxy storefront. Sells access to residential/mobile/datacent
|
|||||||
| Residential | rotating / sticky | IPRoyal `geo.iproyal.com:12321` |
|
| Residential | rotating / sticky | IPRoyal `geo.iproyal.com:12321` |
|
||||||
| Mobile 4G | rotating | IPRoyal `4g.iproyal.com` |
|
| 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
|
## API
|
||||||
- `POST /api/register` — `{username, email, password, captcha_id, captcha}`
|
|
||||||
- `POST /api/login` — `{username, password}`
|
| Route | Body | Purpose |
|
||||||
- `GET /api/captcha` — arithmetic challenge
|
|---|---|---|
|
||||||
- `POST /api/buy` — `{plan_id}` → creates BTCPay invoice + pending subscription
|
| `GET /api/captcha` | — | arithmetic challenge |
|
||||||
- `GET /api/subscriptions` — user's active proxies
|
| `POST /api/register` | `{username, email, password, captcha_id, captcha}` | no-KYC signup |
|
||||||
- `POST /api/btcpay/webhook` — activates subscription + issues creds on payment
|
| `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**.
|
||||||
|
|
||||||
## Deploy
|
## Deploy
|
||||||
```
|
|
||||||
tar czf rigel.tar.gz app.py
|
```sh
|
||||||
|
tar czf rigel.tar.gz app.py proxy_server.py
|
||||||
scp rigel.tar.gz root@10.30.20.85:/tmp/
|
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 && tar xzf /tmp/rigel.tar.gz && systemctl restart rigel'"
|
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
|
## Gotchas
|
||||||
- Fleet tunnel is REMOTE-MANAGED — edit ingress via CF API (`/accounts/<id>/cfd_tunnel/1aeb1ac0.../configurations`), NOT the local `config-fleet.yml`. Local edits are ignored.
|
|
||||||
- BTCPay webhook secret wired via `BTCPAY_WEBHOOK_SECRET` env in `rigel.service`.
|
- **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.
|
||||||
|
|||||||
Reference in New Issue
Block a user