# Sub2SOCKS — minimal subscription-to-SOCKS container **One env var, SOCKS proxy.** Pulls a subscription URL at startup, picks the first VLESS node from it, generates a sing-box JSON config on the fly and starts `sing-box` with a SOCKS5 inbound → VLESS outbound. ## Quick start ```bash docker run -d --name sub2socks \ -p 1080:1080 \ -e SUB_URL="https://your-sub-endpoint.example.com/link/xxxxxxx" \ sub2socks:latest ``` Connect to `socks5://localhost:1080`. ## Environment variables | Variable | Required? | Default | Description | |----------|-----------|----------------------|---------------------------------------------------| | `SUB_URL` | **yes** | — | Subscription group URL (any format with VLESS nodes) | | `SOCKS_PORT` | no | `1080` | SOCKS5 listen port | | `SOCKS_USER` | no | `""` | Auth username (leave empty to skip auth) | | `SOCKS_PASS` | no | `""` | Auth password | | `DNS_SERVER` | no | `udp://1.1.1.1` | Upstream DNS resolver address (insecure UDP by default) | | `PICK_STRATEGY` | no | `first` | Node selection: `first` (default) or `random` | | `LOG_LEVEL` | no | `info` | sing-box log level (`debug`, `warn`, `error`) | ### With auth + local DNS ```bash docker run -d --name sub2socks \ -p 1080:1080 \ -e SUB_URL="https://..." \ -e SOCKS_USER=myuser \ -e SOCKS_PASS=secret \ -e DNS_SERVER=tls://192.168.1.53 # local AdGuard Home, etc. sub2socks:latest ``` ### With random node selection ```bash docker run -d --name sub2socks \ -p 1080:1080 \ -e SUB_URL="https://..." \ -e PICK_STRATEGY=random \ sub2socks:latest ``` ### In Docker Compose ```yaml services: sub2socks: image: sub2socks:latest container_name: sub2socks ports: - "1080:1080" environment: SUB_URL: "https://your-sub-endpoint.example.com/sub/xxxxxxx" DNS_SERVER: "tls://192.168.1.53" # your local AdGuard Home ``` ## How it works 1. **Entrypoint runs** `python3 entrypoint.py` 2. Downloads the subscription content & handles base64-encoded payloads automatically 3. Extracts all VLESS nodes, picks one (`first` or `random`) 4. Writes `/tmp/.sub2socks.json` — a full sing-box config with that node as outbound 5. **Execs** `sing-box run -c /tmp/.sub2socks.json` (process replacement — no Python in the runtime tree) ## Testing connection ```bash docker exec sub2socks python3 -c " import socket, struct s = socket.create_connection(('127.0.0.1', 1080), timeout=15) s.sendall(b'\x05\x01\x00') # handshake (no auth) resp = s.recv(2); assert resp[1] == 0 # no auth needed # CONNECT request to httpbin.org:443 target = b'httpbin.org' req = b'\x05\x01\x00\x03' + bytes([len(target)]) + target + struct.pack('!H', 443) s.sendall(req) resp = s.recv(5) print('OK!' if resp[1] == 0 else 'FAILED') " ``` ## Build from source ```bash docker build -t sub2socks /path/to/sub2socks/ ``` The final image is ~180 MB (python:3.13-slim + sing-box binary).