Skip to content
hapheusPublic

About

Minimal, secure HTTP & SOCKS5 proxy routed through Tor with fail-closed leak protection, non-root execution, and a REST API for circuit rotation and dynamic exit node selection.

Topics

Resources

Contributing

Security policy

Stars

7 stars

Watchers

0 watching

Forks

Repository files navigation

A minimal, secure, and reliable Tor HTTP and SOCKS5 proxy packaged for Docker. torproxy routes traffic through the Tor network with fail-closed protection, non-root execution, an authenticated Tor control interface, and a lightweight JSON REST API for circuit rotation, health monitoring, and dynamic exit node routing.


Architecture

Host Client / Dependent Containers
        │
        ├── HTTP Requests ────────► Privoxy (:8118)
        │                             │ (forward-socks5t)
        ├── SOCKS5 Requests ──────────┼───────────────► Tor Daemon (:9050)
        │                             │                   │
        └── REST Control API ─────► API Server (:8080)   │ (Cookie Auth)
                                      │                   │
                                      └─ ControlPort ─────┘ (:9051 loopback)
                                                          │
                                                          ▼
                                                  Tor Onion Network
                                                          ▼
                                                    Target Website

Quick Start

# 1. Start torproxy in the background
docker compose up -d

# 2. Test HTTP proxy (port 8118)
curl -v -x http://127.0.0.1:8118 https://check.torproject.org/api/ip

# 3. Test SOCKS5 proxy with remote DNS resolution (port 9050)
curl -v --socks5-hostname 127.0.0.1:9050 https://check.torproject.org/api/ip

# 4. Check status via the local REST API
curl http://127.0.0.1:8080/status

# 5. Optional: Route exit traffic through a specific country (e.g. DE or AT)
TORPROXY_COUNTRY=DE docker compose up -d
# or multiple countries:
TORPROXY_COUNTRY=DE,AT docker compose up -d

# 6. Dynamically switch exit country on reconnect without container restart:
curl -X POST "http://127.0.0.1:8080/reconnect?country=DE"
# or with JSON payload:
curl -X POST http://127.0.0.1:8080/reconnect \
  -H "Content-Type: application/json" \
  -d '{"country": "AT", "strict_nodes": true}'

Security Note: In docker-compose.yml, all ports bind strictly to 127.0.0.1 by default. Neither the proxy listeners nor the management API require authentication; do not expose them to untrusted networks.


🚀 Transparent Tor Gateway

Route any existing Docker container's entire outbound TCP and DNS traffic automatically through Tor — without modifying your applications or adding proxy flags.

services:
  torproxy:
    image: hapheus/torproxy:latest
    pull_policy: always
    cap_add:
      - NET_ADMIN
    environment:
      TORPROXY_GATEWAY_MODE: "true"
      TORPROXY_COUNTRY: ${TORPROXY_COUNTRY:-}
    restart: unless-stopped

  # Attach any application container directly to torproxy's network namespace:
  my-app:
    image: curlimages/curl:latest
    network_mode: "service:torproxy"
    depends_on:
      torproxy:
        condition: service_healthy
    command: ["-s", "https://check.torproject.org/api/ip"]

Why use Transparent Gateway mode?

  • Zero Application Changes: No need to configure HTTP_PROXY, ALL_PROXY, or browser arguments.
  • Tor DNSPort (:9053): All DNS requests on port 53 (UDP & TCP) are automatically resolved via Tor to prevent DNS leaks.
  • Fail-Closed Netfilter Kill Switch: All direct clearnet traffic is blocked. If Tor stops or disconnects, connections fail closed immediately.
  • Process-Scoped WAN Bypass: Only the dedicated unprivileged tor user may reach the WAN (owner --uid-owner); the API, Privoxy, and attached app containers cannot bypass the kill switch.
  • IPv6: Tor may bootstrap over IPv6 (its own exception); every other process remains blocked — no IPv6 clearnet leaks.
  • UDP Protection: Unsupported non-DNS UDP traffic (e.g. QUIC/HTTP-3) is blocked with ICMP port-unreachable, ensuring fast fallback to TCP without hangs.
  • See the ready-to-run Transparent Gateway Example for details.

Available Interfaces and Ports

Interface Default Port Internal Service Description
HTTP Proxy 8118 Privoxy HTTP/HTTPS forward proxy routing traffic to Tor. Fails closed (500/503) if Tor is disconnected.
SOCKS5 Proxy 9050 Tor Direct Tor SOCKS5 listener. Supports remote DNS resolution via socks5h://.
REST API 8080 Python REST API JSON management and health endpoint. Circuit rotation and connection management.
TransPort (Gateway Mode) 9040 Tor Transparent TCP proxy redirect listener when TORPROXY_GATEWAY_MODE=true.
DNSPort (Gateway Mode) 9053 Tor Transparent DNS resolver listener when TORPROXY_GATEWAY_MODE=true.

REST API Reference

The lightweight API server on port 8080 manages circuits and monitors health without requiring clients to implement the Tor Control Protocol.

Endpoint Method Status Code Purpose Example Response
/status, / GET, POST 200 Connection status and current exit IP. {"status":"connected","ip":"198.51.100.42"}
/ip GET 200, 503 Current verified Tor exit IP. Returns 503 while bootstrapping. {"ip":"198.51.100.42"}
/health, /v1/health GET 200, 503 Structured diagnostic health state across Tor, proxies, and egress. {"status":"healthy","tor":{"bootstrapped":true,"progress":100},"proxies":{"socks5":true},"egress":{"verified":true,"ip":"..."}}
/diagnostics, /v1/diagnostics GET 200 Operational telemetry (uptime, reconnect counts, bootstrap progress). {"uptime_seconds":120,"reconnect_total":2,"tor":{"bootstrapped":true}}
/metrics, /v1/metrics GET 200 Prometheus exposition format metrics for scrapers. Plaintext Prometheus metrics.
/reconnect POST (or GET) 200, 400 Request new circuit (SIGNAL NEWNYM). Supports ?country=DE or JSON body. Clears IP cache. {"action":"reconnect","status":"success","exit_country":"DE"}
/disconnect POST (or GET) 200 Pause Tor network traffic (DisableNetwork=1). Fails closed. {"action":"disconnect","status":"success"}
/connect POST (or GET) 200, 400 Resume Tor network traffic (DisableNetwork=0). Supports ?country=DE or JSON body. {"action":"connect","status":"success"}

HTTP Methods: POST is recommended for state mutations (/reconnect, /disconnect, /connect). Legacy GET calls remain fully supported for backward compatibility. Mutations presented with a foreign browser Origin/Referer are rejected with 403 Forbidden (CSRF protection); curl/script calls without those headers are unaffected. Authentication (Recommended): Unauthenticated by default for backward compatibility. Setting TORPROXY_API_TOKEN (or TORPROXY_API_KEY) protects all endpoints with Authorization: Bearer <token> or X-API-Key: <token>. Detailed schema definitions are documented in docs/api.md.


Container Health Checks

torproxy includes a ready-aware Docker health check (docker/healthcheck.sh). A container reports healthy only when:

  1. Privoxy and Tor daemons are running under non-root user.
  2. Tor bootstrap is 100% complete (bootstrapped=done).
  3. SOCKS5 listener on port 9050 passes greeting handshake.
  4. Egress IP is confirmed through Tor (IsTor: true).

In Docker Compose, dependent services can wait for genuine Tor readiness using service_healthy:

services:
  app:
    image: my-scraper:latest
    depends_on:
      torproxy:
        condition: service_healthy

Configuration

Default settings require no configuration. You can customize listening ports and bindings via environment variables in a .env file or Compose environment section:

Variable Default Allowed Values Description
TORPROXY_LISTEN_ADDRESS 0.0.0.0 Valid IPv4 Bind address for Privoxy inside the container.
TORPROXY_LISTEN_PORT 8118 1024–65535 HTTP proxy listening port inside the container.
TORPROXY_HOST_PORT 8118 1–65535 Host port mapped to HTTP proxy in docker-compose.yml.
TORPROXY_API_PORT 8080 1024–65535 REST API listening port (host and container).
TORPROXY_SOCKS_PORT 9050 1024–65535 Tor SOCKS5 proxy port (host and container).
TORPROXY_COUNTRY (unset) ISO 3166-1 alpha-2 (e.g. DE, AT, US, DE,AT) Route Tor exit circuits through specific countries using tor-geoipdb.
TORPROXY_STRICT_NODES 0 0, 1, true, false, yes, no When 1/true, reject circuits if configured country exit nodes are unavailable.
TORPROXY_GEOIP_AUTO_UPDATE 0 0, 1, true, false, yes, no Opt-in: periodically download Tor's GeoIP database (geoip/geoip6) from Tor Project GitLab and reload Tor. On failure the bundled/previous database keeps working. See GeoIP auto-update.
TORPROXY_API_TOKEN (unset) String Optional: Bearer token / API key securing REST API port 8080. Recommended for production.
TORPROXY_API_ALLOW_ANONYMOUS_HEALTH 0 0, 1, true, false Optional: Allow unauthenticated /health probing when TORPROXY_API_TOKEN is set.
TORPROXY_GATEWAY_MODE 0 0, 1, true, false, yes, no Enable Transparent Tor Gateway mode (TransPort, DNSPort, netfilter kill switch). Requires cap_add: [NET_ADMIN].
TORPROXY_TRANS_PORT 9040 1024–65535 Listening port for Tor TransPort when gateway mode is enabled.
TORPROXY_DNS_PORT 9053 1024–65535 Listening port for Tor DNSPort when gateway mode is enabled.

All variables are strictly validated at startup. Port conflicts or out-of-range values trigger an immediate diagnostic failure. See docs/configuration.md for full details.

GeoIP Auto-Update

By default torproxy uses the Tor GeoIP database bundled with the Alpine Tor package (/usr/share/tor/geoip{,6}), which is only refreshed when the Docker image is rebuilt. To keep country routing (TORPROXY_COUNTRY=DE) on a fresh IP-to-country mapping, enable the opt-in auto-update:

TORPROXY_GEOIP_AUTO_UPDATE=1 TORPROXY_COUNTRY=DE docker compose up -d

With TORPROXY_GEOIP_AUTO_UPDATE=1 the container downloads geoip/geoip6 from Tor Project GitLab (HTTPS) at startup and then every TORPROXY_GEOIP_UPDATE_INTERVAL seconds (default 86400 = 24h), validates the format, installs the files atomically into TORPROXY_GEOIP_DIR (default /var/lib/tor/geoip), and sends Tor SIGHUP to reload them. If the download or validation fails (e.g. offline or upstream unavailable), the previously installed — or bundled — database keeps working, so an old version never breaks country routing. Each attempt is recorded and exposed additively as geoip in /status, so a silent fallback is visible. The pre-publish Live Image Verification gate checks that the GeoIP URLs are reachable and that a container with auto-update enabled downloads the database; the Daily Live Image Verification workflow repeats this as a drift detector. Additional settings: TORPROXY_GEOIP_URL, TORPROXY_GEOIP6_URL, TORPROXY_GEOIP_MAX_BYTES, TORPROXY_GEOIP6_MAX_BYTES.


Shipped Examples

Ready-to-run use cases with hardened configurations:

Example Purpose Guide
Transparent Tor Gateway Route any container's entire TCP & DNS traffic automatically through Tor without proxy settings. View Example
Hardened Production Read-only rootfs, dropped capabilities, and memory-backed tmpfs. View Example
Browserless Chromium Headless browser automation and scraping routed through Tor. View Example
CRW Web Scraper High-performance webpage-to-Markdown scraper via Tor proxy. View Example
SearXNG Metasearch Private, self-hosted search engine routing upstream queries via Tor. View Example

Security Model and Trust Boundaries

  • Non-Root Execution: The container init starts as root only to drop privileges — every daemon runs as an unprivileged user (tor, privoxy, torproxy). In gateway mode the netfilter WAN bypass is scoped to the dedicated tor UID, so the API/Privoxy cannot reach the WAN directly (ISSUE-03).
  • Authenticated ControlPort: Tor's control port (127.0.0.1:9051) requires ephemeral filesystem cookie authentication (CookieAuthentication 1).
  • Fail-Closed Guarantee: If Tor disconnects or crashes, Privoxy drops traffic and returns HTTP 503 instead of leaking to clearnet.
  • DNS Leak Prevention: To prevent local DNS leaks, always use remote DNS resolution with SOCKS5 (curl --socks5-hostname 127.0.0.1:9050 or socks5h://).
  • Threat Model: See SECURITY.md for vulnerability reporting procedures, threat boundaries, and anonymity limitations.
  • Hardening Guide: See docs/hardening.md for read-only rootfs and dropped Linux capabilities.

Project Documentation


Contributing

We welcome contributions! Please review our Contributing Guidelines and Code of Conduct. All PRs must maintain backward compatibility, include hermetic unit tests, and maintain >= 90% test coverage.


License

Released under the MIT License.


💝 Support the Project

If you find this project helpful, consider showing some support:

  • ☕ Buy me a coffee: Send a tip via PayPal.
  • ❤️ Charity Donation: Donate to Österreichische Krebshilfe (Austrian Cancer Aid) or any local animal welfare organization.
  • 🎯 Dream Support: I would love some tickets for the World Darts Championship at Ally Pally (Alexandra Palace) – hopefully, I will make it there one day!

About

Minimal, secure HTTP & SOCKS5 proxy routed through Tor with fail-closed leak protection, non-root execution, and a REST API for circuit rotation and dynamic exit node selection.

Topics

Resources

Contributing

Security policy

Stars

7 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages