user b72d083f56 feat: wire control API into server and config
Add api_host/api_port to Config dataclass, parse api_listen key in
load_config(), add --api [HOST:]PORT CLI flag. Start/stop API server
in serve() alongside the SOCKS5 listener.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-16 19:03:44 +01:00

s5p

SOCKS5 proxy server with Tor and proxy-chain support. Routes connections through configurable chains of SOCKS4, SOCKS5, and HTTP CONNECT proxies.

Features

  • SOCKS5 server (RFC 1928)
  • Proxy chaining: tunnel through multiple hops in sequence
  • Supported hop protocols: SOCKS5, SOCKS4/4a, HTTP CONNECT
  • Per-hop authentication (username/password)
  • DNS leak prevention (domain names forwarded to proxies, never resolved locally)
  • Tor integration (Tor is just another SOCKS5 hop)
  • Managed proxy pool: multiple sources (API + file), health-tested, weighted selection
  • Per-proxy failure backoff (60s cooldown), stale proxy expiry, chain pre-flight
  • Fast warm start (seconds on restart vs minutes on cold start)
  • Connection retry with proxy rotation (configurable attempts)
  • Dead proxy reporting to upstream API (optional report_url)
  • SIGHUP hot reload (timeout, retries, log_level, pool config)
  • Connection metrics with pool stats (logged periodically and on shutdown)
  • Concurrent connection limit with backpressure (max_connections)
  • Async HTTP client for proxy source fetching (parallel, no threads)
  • First-hop TCP connection pool (pre-warmed, stale-evicted)
  • Container-ready (Alpine-based, podman/docker)
  • Graceful shutdown (SIGTERM/SIGINT)
  • Pure Python, asyncio-based, minimal dependencies

Quick Start

# Install locally
cd ~/git/s5p
python -m venv .venv && source .venv/bin/activate
pip install -e .

# Run with Tor
s5p -C socks5://127.0.0.1:9050

# Run with config file
cp config/example.yaml config/s5p.yaml  # edit with your proxies
s5p -c config/s5p.yaml

# Test it
curl --proxy socks5h://127.0.0.1:1080 https://check.torproject.org/api/ip

Container

make build   # podman-compose build
make up      # podman-compose up -d
make logs    # podman-compose logs -f
make down    # podman-compose down

Source, config, and data are bind-mounted, not baked into the image. Pool state and profile output persist in ~/.cache/s5p/ (/data inside container).

Configuration

Copy the example and edit with your proxy chain:

cp config/example.yaml config/s5p.yaml
listen: 127.0.0.1:1080
timeout: 10
retries: 3
max_connections: 256                  # concurrent connection limit
pool_size: 8                          # pre-warmed connections to first hop

chain:
  - socks5://127.0.0.1:9050          # Tor

proxy_pool:
  sources:
    - url: http://10.200.1.250:8081/proxies
      proto: socks5
    - file: /etc/s5p/proxies.txt     # one proxy URL per line
  refresh: 300                        # re-fetch interval (seconds)
  test_interval: 120                  # health test cycle (seconds)
  max_fails: 3                        # evict after N consecutive failures

config/s5p.yaml is gitignored; config/example.yaml is the tracked template.

CLI Reference

s5p [-c FILE] [-l [HOST:]PORT] [-C URL[,URL,...]] [-S URL] [-t SEC] [-r N] [-m N] [-v|-q]

Options:
  -c, --config FILE        YAML config file
  -l, --listen [HOST:]PORT Listen address (default: 127.0.0.1:1080)
  -C, --chain URL[,URL]    Comma-separated proxy chain
  -S, --proxy-source URL   Proxy source API URL
  -t, --timeout SEC        Per-hop timeout (default: 10)
  -r, --retries N          Max attempts per connection (default: 3, proxy_source only)
  -m, --max-connections N  Max concurrent connections (default: 256)
  -v, --verbose            Debug logging
  -q, --quiet              Errors only
  --cprofile [FILE]        Enable cProfile, dump to FILE (default: s5p.prof)
  -V, --version            Show version

How Chaining Works

Client -> s5p -> [static chain] -> [weighted alive proxy from pool] -> Destination

s5p connects to Hop1 via TCP, negotiates the hop protocol (SOCKS5/4/HTTP), then over that tunnel negotiates with Hop2, and so on. If a proxy pool is configured, an alive proxy is appended per-connection, weighted toward those with the most recent successful health test. Each hop only sees its immediate neighbors.

Description
No description provided
Readme 769 KiB
Languages
Python 99.6%
Makefile 0.2%
Dockerfile 0.2%