Small Go web service that proxies outbound GET requests through a SOCKS5 proxy.
It exposes one business endpoint:
GET /socks5(also available asGET /proxy)
and one technical endpoint:
GET /health
/socks5 accepts a target URL via query params, enforces Bearer token auth, forwards the request through SOCKS5, and returns upstream response as-is.
Flow:
- Validate
Authorizationheader:Bearer <token>. - Read query params:
url(required iftargetnot set): full HTTPS URL used as-istarget(required ifurlnot set): host/path without protocol, service prependshttps://method(required): onlygetsupported (case-insensitive)data_type(optional): currently ignored, kept for compatibility
- Only HTTPS targets are allowed. HTTP URLs are rejected with
400. - If
TOKENBEL_PROXY_ALLOWED_DOMAINSis configured, only requests to listed domains (including subdomains) are allowed. - Execute request through SOCKS5 proxy with per-request timeout.
- Return upstream status code, headers, and body.
Error behavior:
- Missing/invalid Bearer token ->
401 - Missing
url/target->400 - HTTP (non-HTTPS) target ->
400 - Disallowed domain ->
403 - Invalid
method->400 - Rate limit exceeded ->
429 - Upstream timeout ->
504 - Proxy/upstream network error ->
502
Error response shape:
{
"error": "bad_gateway",
"message": "proxy connection failed",
"details": "connection refused"
}Configuration is read from environment variables:
| Variable | Required | Description |
|---|---|---|
TOKENBEL_PROXY_BEARER_TOKEN |
Yes | Bearer token for endpoint authentication |
TOKENBEL_PROXY_SOCKS5_URL |
Yes | SOCKS5 proxy URL (e.g., socks5://user:pass@host:port) |
TOKENBEL_PROXY_PORT |
No | Server port (default: 8080) |
TOKENBEL_PROXY_TIMEOUT |
No | Upstream request timeout in seconds (default: 120) |
TOKENBEL_PROXY_CLIENT_PROFILE |
No | TLS client profile: chrome_120 or firefox_117 (default: chrome_120) |
TOKENBEL_PROXY_INSECURE_TLS |
No | Skip TLS verification: true or false (default: true) |
TOKENBEL_PROXY_ALLOWED_DOMAINS |
No | Comma-separated domain allowlist (default: empty = all allowed) |
TOKENBEL_PROXY_RATE_LIMIT |
No | Requests per second per IP (default: 0 = unlimited) |
TOKENBEL_PROXY_RATE_BURST |
No | Burst size for rate limiter (default: same as rate limit) |
export TOKENBEL_PROXY_BEARER_TOKEN="your-secret-token"
export TOKENBEL_PROXY_SOCKS5_URL="socks5://user:password@geo.iproyal.com:12321"
export TOKENBEL_PROXY_ALLOWED_DOMAINS="egr.gov.by,example.com"
export TOKENBEL_PROXY_RATE_LIMIT=5The service will exit at startup if required variables are missing.
GET /health
Checks SOCKS5 proxy TCP reachability. Returns 200 if proxy is reachable, 503 if not.
Success response:
{ "status": "ok" }Unhealthy response:
{ "status": "unhealthy", "details": "proxy unreachable" }GET /socks5?url=<https-url>&method=get
GET /socks5?target=<host/path>&data_type=json&method=get
Required header:
Authorization: Bearer $TOKENBEL_PROXY_BEARER_TOKENA X-Request-ID header is set on every response. If the incoming request includes one, it is forwarded; otherwise a random ID is generated.
Example:
curl -i \
-H "Authorization: Bearer $TOKENBEL_PROXY_BEARER_TOKEN" \
"http://localhost:8080/socks5?target=egr.gov.by/api/v2/egr/getAllJurNamesByRegNum/191179355&data_type=json&method=get"From project root:
cd src
go mod tidy
go build -o proxy .
./proxyThe service starts on :8080.
Quick checks:
curl -s http://localhost:8080/healthcurl -i "http://localhost:8080/socks5?target=example.com&method=get"
# expected: 401 (missing auth header)Run all checks:
cd src
go test ./...
go vet ./...
go build ./...Current unit tests are in:
handler/proxy_test.gohandler/health_test.gohandler/ratelimit_test.gohandler/requestid_test.goconfig/config_test.go
Covered scenarios:
- unauthorized requests
- missing target
- invalid method
- HTTPS-only enforcement
- domain allowlist (allowed, blocked, subdomains)
- per-request timeout (504)
- request ID generation and forwarding
- rate limiting (under/over limit, separate IPs)
- health check (proxy reachable, unreachable, no proxy configured)
- timeout mapping
- bad gateway mapping
- success response forwarding
- config env var parsing
Service includes a multi-stage Dockerfile:
- Builder:
golang:alpine - Runtime:
alpine:latest
From repository root:
docker build -t tokenbel-proxy:latest ./srcdocker run --rm -p 8080:8080 \
-e TOKENBEL_PROXY_BEARER_TOKEN="$TOKENBEL_PROXY_BEARER_TOKEN" \
-e TOKENBEL_PROXY_SOCKS5_URL="$TOKENBEL_PROXY_SOCKS5_URL" \
tokenbel-proxy:latestcurl -s http://localhost:8080/healthFor production-like deployment, at minimum:
- Restrict inbound access (private network, gateway, ACLs).
- Set
TOKENBEL_PROXY_ALLOWED_DOMAINSto limit upstream targets. - Enable rate limiting via
TOKENBEL_PROXY_RATE_LIMIT. - Set
TOKENBEL_PROXY_INSECURE_TLS=falseif upstream certificates are valid. - Monitor logs (structured JSON via
log/slog) and HTTP status distribution.