How to Hide Your Service from Prying Eyes (Using Tor as a Tunnel to the Open Internet)

Blog

Introduction

At Trustcrypt, we understand that privacy and resilience against unwanted attention are crucial when hosting services online. Whether you run a web app, a gaming server, or any other type of online service, ensuring anonymity and uninterrupted availability can be a top priority.

This article introduces TORTCB (Tor TCP Chain Balancer) – a handy solution that sets up multiple Tor hidden services, then balances incoming traffic across them. The project is open-source on GitHub. Below, we explain what it does, why it might be useful, and how you can set it up.

Why Hide Your Service?

Tor can do a lot for you:

  • Provide anonymity: When a server is placed behind a .onion address, its real IP and physical location remain hidden.
  • Streamline access without public IPs: No need for manual port forwarding or obtaining a public IP address.
  • Protect privacy: Only you know your server’s real IP. Externally, only the .onion address is visible.

However, a typical Tor hidden service uses a single Tor process and a single tunnel. If you want extra redundancy or want to handle higher traffic by distributing load across multiple .onion addresses, TORTCB does exactly that.

What Is TORTCB?

TORTCB (Tor TCP Chain Balancer) is essentially two Docker images working in tandem:

  1. tor_forward:
    • Spins up multiple Tor hidden services.
    • Each service listens on a unique .onion domain and forwards traffic to a local port (where your actual app runs).
    • Generates a domains.list file containing all the new .onion domains and their corresponding ports.
  2. haproxy_receiver:
    • Reads the domains.list file and launches a dedicated Tor client for each .onion domain, ensuring each has its own isolated Tor process.
    • Uses socat to receive traffic separately for each onion domain.
    • Aggregates everything with HAProxy, combining all Tor tunnels into a single front-end listening port.

The end result is a cluster of .onion addresses (for redundancy) consolidated behind one external HAProxy port, enabling a robust load balancing setup for Tor hidden services.

How It Works in Practice

  1. Multiple Onion Addresses: tor_forward creates several .onion domains.
  2. Unified Entry Point: haproxy_receiver merges traffic from those domains into one HAProxy port.
  3. Load Spreading: Instead of overloading one single Tor tunnel, your incoming connections are distributed across multiple .onion endpoints.

A simplified diagram:

[User] -> .onion addresses -> [tor_forward] -> localhost:5000 (your app)
                                     |
                                     v
[HAProxy on a single port] ->[haproxy_receiver]

You can choose to connect through any of the .onion addresses, or simply direct all users to that single HAProxy entry port (useful for local or external balancing).

Quick Start

1. Requirements

  • Docker and (preferably) Docker Compose.
  • The TORTCB repository: GitHub – keklick1337/tortcb.
  • An application running locally, for example on port 5000, that you want hidden behind Tor.

2. Clone the Repository

git clone https://github.com/keklick1337/tortcb.git
cd tortcb

Inside, you will see two main folders: tor_forward/ and haproxy_receiver/.

Setting Up tor_forward

tor_forward is the container that creates multiple Tor hidden services, each forwarding traffic to your actual application.

Build the Docker image:

cd tor_forward
docker build -t tor_forward .

Run the container:

docker run -d \
  --name tor_forward \
  -e HOST_IP=host.docker.internal \
  -e HOST_PORT=5000 \
  -e TOR_INSTANCES=3 \
  -e RANDOM_PORT_START=20000 \
  -v $(pwd)/data/tor_forward:/var/lib/tor/hidden_services \
  tor_forward

Key parameters:

  • HOST_IP / HOST_PORT: IP and port of the application you’re hiding (e.g., 5000).
  • TOR_INSTANCES: Number of .onion addresses to generate.
  • RANDOM_PORT_START: The initial port number Tor will start binding to on your host.

After launching, check ./data/tor_forward/domains.list for lines like:

abcde12345.onion:20000
fghij67890.onion:20001

Each .onion domain maps to a local port.

Setting Up haproxy_receiver

haproxy_receiver reads all .onion domains from the domains.list file, starts a Tor client and socat for each one, and then merges them behind HAProxy.

Build the Docker image:

cd ../haproxy_receiver
docker build -t haproxy_receiver .

Run the container:

docker run -d \
  --name haproxy_receiver \
  -e HAPROXY_LISTEN_PORT=9080 \
  -e BASE_LOCAL_PORT=30000 \
  -e BASE_SOCKS_PORT=9050 \
  -e STATS_PORT=9090 \
  -e STATS_USER=admin \
  -e STATS_PASS=mypassword \
  -v /path/to/domains.list:/etc/domains.list:ro \
  -p 9080:9080 \
  -p 9090:9090 \
  haproxy_receiver

Key parameters:

  • -v /path/to/domains.list:/etc/domains.list:ro: Points to the domains.list file generated by tor_forward.
  • HAPROXY_LISTEN_PORT=9080: The port exposed by HAProxy (mapped to -p 9080:9080).
  • STATS_PORT=9090, STATS_USER=admin, STATS_PASS=mypassword: Optional HAProxy stats page credentials.

After launching, the logs will confirm each .onion domain is paired with its own Tor process and socat listener, all combined into HAProxy on port 9080.

Verifying Your Setup

  1. Check Your App: Make sure your target service is up on HOST_IP:HOST_PORT (for instance, localhost:5000).
  2. Test an Onion Address: Pick any generated onion domain (e.g., abcde12345.onion:20000). Try connecting to it via Tor Browser or curl through a SOCKS proxy. You should reach your service anonymously.
  3. Check HAProxy: Port 9080 will be your consolidated external entry point. You can open that port publicly, tunnel it, or restrict it behind a VPN—whatever suits your environment.
  4. HAProxy Stats: Go to http://:9090/stats, enter the credentials you set, and view connection and load metrics in real time.

Using Docker Compose

For convenience, you can automate everything with a docker-compose.yml. Below are two sample files—one for each container. Adjust them to suit your environment.

docker-compose.yml for tor_forward:

version: "3.8"

services:
  tor_forward:
    build: ./tor_forward
    container_name: tor_forward
    environment:
      - HOST_IP=host.docker.internal
      - HOST_PORT=5000
      - TOR_INSTANCES=5
      - RANDOM_PORT_START=20000
    volumes:
      - ./data/tor_forward:/var/lib/tor/hidden_services

docker-compose.yml for haproxy_receiver:

version: "3.8"

services:
  tor_forward:
    build: ./tor_forward
    container_name: tor_forward
    environment:
      - HOST_IP=host.docker.internal
      - HOST_PORT=5000
      - TOR_INSTANCES=5
      - RANDOM_PORT_START=20000
    volumes:
      - ./data/tor_forward:/var/lib/tor/hidden_services

Once configured, run:

docker-compose up -d --build

This spawns both containers. tor_forward generates the domains.list, while haproxy_receiver automatically sets up Tor, socat, and HAProxy for each onion domain.

Tips and Caveats

  • IP Address Issues on Linux: host.docker.internal may not work on some Linux distributions. Use a real IP (e.g., 172.17.0.1) or localhost instead, or consider network: host mode.
  • Resource Usage: Spinning up multiple .onion domains can be CPU-intensive. Each instance runs a Tor client plus socat, so don’t overdo it if your server has limited resources.
  • Preserving Onion Addresses: As long as you keep the same volume (./data/tor_forward), the generated .onion addresses remain the same across container restarts.
  • Security: For a purely hidden service, you don’t need to map HAProxy’s port 9080 to the outside world. You can keep it internal within a Docker network, so all external traffic goes solely through .onion addresses.
  • Scaling: If you want more .onion addresses, just increase TOR_INSTANCES in tor_forward. Then update your system resources accordingly.

Conclusion

With TORTCB, you can hide your server behind multiple Tor hidden services while balancing load across several tunnels. The process is made simple through Docker containers or Docker Compose, providing:

  • Anonymity: True .onion addresses with no exposed IP.
  • Scalability: Multiple Tor tunnels for traffic distribution and resilience.
  • Convenience: Quick, containerized deployment using a minimal config.

Explore the TORTCB GitHub repository to dive deeper, open issues, or contribute. Enjoy building faster, safer, and more private services with Tor and TORTCB!

© 2025 Trustcrypt. All rights reserved.