Table of Contents
This image combines TOR and haproxy to create a local DNS proxy through TOR to CloudFlare's hidden DNS resolver
https://dns4torpnlfs2ifuz2s2yf3fc7rdmsbhm6rw75euj35pac6ap25zgqad.onion/haproxy provides industrial-grade TCP proxying with native SOCKS4 support for Tor routing, built-in health checks, and automatic failover — replacing the shell-based failover logic entirely.
- Clients connect to the container via DNS-over-TLS on port 853
- haproxy relays the raw TCP stream (TLS passthrough) to an upstream DNS-over-TLS resolver
- haproxy's native SOCKS4 support routes connections through Tor's SOCKS proxy on port 9050
- Tor's MapAddress directive maps a virtual IP (10.192.0.1) to Cloudflare's .onion resolver
- haproxy performs health checks against all upstreams and automatically fails over if the primary goes down
Unlike tor-socat, the failover is fully handled by haproxy — no shell scripts parsing stderr.
To use it as upstream server for other docker containers your command may look like:
docker run -d --name=tor-haproxy --restart=always sureserver/tor-haproxy:latestIf you want to access it from your host, publish port 853 like this:
docker run -d --name=tor-haproxy -p 853:853 --restart=always sureserver/tor-haproxy:latestThis image uses obfs4 bridges to access tor network. There is a pair of them in this image. If you want to use another ones, just do it like this:
docker run -d --name=tor-haproxy -e BRIDGE1="obfs4 IP:PORT FINGERPRINT cert=... iat-mode=0" -e BRIDGE2="obfs4 IP:PORT FINGERPRINT cert=... iat-mode=0" --restart=always sureserver/tor-haproxy:latestwith your desired bridges' strings in quotesAfter that just use IP-address of your container and port 853 as DNS-over-TLS upstream resolver
All the same commands work with Podman by replacing
dockerwithpodman:
podman run -d --name=tor-haproxy --restart=always sureserver/tor-haproxy:latestWith host port published:
podman run -d --name=tor-haproxy -p 853:853 --restart=always sureserver/tor-haproxy:latestWith custom bridges:
podman run -d --name=tor-haproxy -e BRIDGE1="obfs4 IP:PORT FINGERPRINT cert=... iat-mode=0" -e BRIDGE2="obfs4 IP:PORT FINGERPRINT cert=... iat-mode=0" --restart=always sureserver/tor-haproxy:latestTo generate a systemd service for auto-start:
podman generate systemd --name tor-haproxy --new > ~/.config/systemd/user/tor-haproxy.service
systemctl --user enable --now tor-haproxy.service
| tor-socat | tor-haproxy | |
|---|---|---|
| Local protocol | TLS passthrough | TLS passthrough (identical client behavior) |
| Failover | Shell-based health checks (dig probe every 30s) |
haproxy health checks (inter 30s fall 3 rise 2) |
| Tor routing | socat SOCKS4A | haproxy native socks4 keyword |
| .onion support | SOCKS4A hostname resolution | Tor MapAddress to virtual IP |
| Health monitoring | Active DNS health checks every 30s | Active TCP health checks every 30s |
| Connection logging | socat debug output | haproxy tcplog |
See the open issues for a list of proposed features (and known issues).
If you want to say thank you or/and support active development of tor-haproxy:
- Add a GitHub Star to the project.
- Tweet about the tor-haproxy.
- Write interesting articles about the project on Dev.to, Medium or your personal blog.
Together, we can make tor-haproxy better!
The original setup of this repository is by Serverman.
For a full list of all authors and contributors, see the contributors page.
tor-haproxy follows good practices of security, but 100% security cannot be assured. tor-haproxy is provided "as is" without any warranty. Use at your own risk.
This project is licensed under the MIT license.
See LICENSE for more information.