How to Hide Your Service from Prying Eyes (Using Tor as a Tunnel to the Open Internet)
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:
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.
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.
- Reads the
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
- Multiple Onion Addresses:
tor_forward
creates several.onion
domains. - Unified Entry Point:
haproxy_receiver
merges traffic from those domains into one HAProxy port. - 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 thedomains.list
file generated bytor_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
- Check Your App: Make sure your target service is up on
HOST_IP:HOST_PORT
(for instance,localhost:5000
). - Test an Onion Address: Pick any generated onion domain (e.g.,
abcde12345.onion:20000
). Try connecting to it via Tor Browser orcurl
through a SOCKS proxy. You should reach your service anonymously. - 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. - HAProxy Stats: Go to
http://
, enter the credentials you set, and view connection and load metrics in real time.:9090/stats
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
) orlocalhost
instead, or considernetwork: host
mode. - Resource Usage: Spinning up multiple
.onion
domains can be CPU-intensive. Each instance runs a Tor client plussocat
, 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 increaseTOR_INSTANCES
intor_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.