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

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 tls://8.8.8.8 Upstream DNS resolver address
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

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

docker run -d --name sub2socks \
  -p 1080:1080 \
  -e SUB_URL="https://..." \
  -e PICK_STRATEGY=random \
  sub2socks:latest

In Docker Compose

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

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

docker build -t sub2socks /path/to/sub2socks/

The final image is ~180 MB (python:3.13-slim + sing-box binary).

S
Description
No description provided
Readme 49 KiB
Languages
Python 97.6%
Dockerfile 2.4%