tor-socks-proxy runs Tor as a SOCKS5 client in a 10MB container
🐳 Tiny Docker image (🤏 10MB) as 🧅 Tor SOCKS5 proxy 🛡
At a glance
- What is it?
- tor-socks-proxy is a Docker image, roughly 10 MB, that starts Tor inside Alpine and exposes it as a SOCKS5 proxy on port 9150, with optional DNS over Tor on 8853 over UDP. It is deliberately a client only, with relay and exit node function disabled, so nothing you run it as can accidentally contribute to the Tor network. The last push was on 2026-06-10 and there are no tagged releases.
- Who is it for?
- Adopt tor-socks-proxy when you want a disposable Tor SOCKS5 endpoint for one application, on a machine where you do not want to install Tor on the host and do not want to risk becoming a relay by accident. Do not adopt it if you need an authenticated proxy for untrusted users, an exit or bridge node, or reproducible builds, since the image tracks Alpine edge packages and no release tags are published.
- Can I use it commercially?
- Yes, with conditions. GPL-3.0 is a copyleft licence: if you distribute software that includes it, you must release that software's source code under the same licence. Running it internally without distributing it does not trigger that obligation.
- Is it still maintained?
- Yes. The repository last received commits 135 days ago.
- What is it written in?
- Mainly Dockerfile, according to GitHub's language statistics.
Answers come from the project's GitHub data, last synced on October 22, 2026, and from our analysis. They are not legal advice.
Editorial analysis
A client, not a relay, by design
tor-socks-proxy packages one thing: a Tor client listening as a SOCKS5 proxy. The project describes it as the easy way to set up a Tor SOCKS5 proxy server inside a Docker container, and it adds the qualifier that matters most, without Tor relay or exit node function enabled.
That qualifier is the design decision. Tor clients, relays and exit nodes are different roles with different consequences, and a container that started a relay would contribute bandwidth and be visible to the network by accident. Restricting the role means the container is safe to run on a home machine, on a CI runner or on a shared VPS, and it also means the image is not a way to run a bridge.
The image is published in two places. Docker Hub carries peterdavehello/tor-socks-proxy and the GitHub Container Registry carries ghcr.io/peterdavehello/tor-socks-proxy, and the README says to use the ghcr.io/ prefix if you prefer that registry. The repository is small and mostly declarative: a Dockerfile, a torrc file, a docker-compose.yml, a .dockerignore and a renovate configuration for dependency updates.
The project is GPL-3.0 licensed, and the README notes that development and testing are sponsored by DigitalOcean.
One docker run gives you a SOCKS5 proxy on localhost
The first-time setup is a single command:
docker run -d --restart=always --name tor-socks-proxy -p 127.0.0.1:9150:9150/tcp peterdavehello/tor-socks-proxy:latestTwo flags carry most of the meaning. The restart policy makes the container come back after a reboot without anyone logging in. The port mapping binds the published port to 127.0.0.1, and the README is explicit that you should not change that address unless you deliberately want to expose the proxy to a local network or to the internet.
The README also warns about a port collision: ports 9050 and 9150 may be occupied if another Tor client such as Tor Browser is running, and you can change the first 9150 to any available port. That is the host side of the mapping, so it is the part you adjust.
Once it is running, the container lifecycle is ordinary Docker:
docker start tor-socks-proxydocker stop tor-socks-proxyand the logs are where you check that the client actually bootstrapped into the network:
docker logs tor-socks-proxyTo confirm traffic really goes through Tor, the README gives a curl invocation that asks for the IP address the outside world sees:
curl --socks5-hostname 127.0.0.1:9150 https://ipinfo.tw/ipThe socks5-hostname option matters for more than convenience. It sends the hostname to the proxy for resolution rather than resolving it locally, so the DNS lookup happens inside the Tor tunnel instead of leaking the name to your own resolver.
The Dockerfile is a short Alpine build with an edge package policy
The whole image is defined by a handful of instructions. It starts from alpine:3.24, adds the Alpine edge community and testing repositories, upgrades the package index, and installs three packages: tor, obfs4proxy and curl.
FROM alpine:3.24
LABEL maintainer="Peter Dave Hello <[email protected]>"
LABEL name="tor-socks-proxy"
LABEL version="latest"Two details in that block are worth noticing. The tor and obfs4proxy packages are taken from the edge repositories rather than from stable, which is what makes a fresh Tor available, and the choice also means the package versions move under you when the image is rebuilt. The second is that curl is installed only so the healthcheck has a client to test with.
The image then copies the torrc from the repository root into /etc/tor/, tightens the permissions on the Tor data directory, and switches to an unprivileged user before starting Tor as its entrypoint:
USER tor
EXPOSE 8853/udp 9150/tcp
CMD ["/usr/bin/tor", "-f", "/etc/tor/torrc"]The exposed ports match the two features the project offers, TCP 9150 for SOCKS5 and UDP 8853 for DNS over Tor.
The healthcheck is a single curl against a long onion address, run through the local SOCKS5 proxy:
HEALTHCHECK --timeout=10s --start-period=60s \
CMD curl --fail --socks5-hostname localhost:9150 -I -L 'https://www.facebookwkhpilnemxj7asaniu7vnjjbiltxjqhye3mhbshg7kx5tfyd.onion/' || exit 1A 60 second start period is right for Tor, since bootstrapping takes a while. The trade is that the check depends on a specific onion service being reachable, which is a dependency outside your control and outside the container.
DNS over Tor needs a second published port
A SOCKS5 proxy only carries the traffic you send through it, so name resolution is a separate question. The project answers it with the Tor DNS port, published as UDP 8853, and the README describes the setup as publishing the DNS port so that DNS requests can be queried over Tor.
docker run -d --restart=always --name tor-socks-proxy -p 127.0.0.1:9150:9150/tcp -p 127.0.0.1:53:8853/udp peterdavehello/tor-socks-proxy:latestThe mapping here is different from the SOCKS one. The host port is 53, which is the standard DNS port, while the container port is 8853, so the client on the host believes it is talking to a normal resolver and the container is serving Tor DNS on its own port.
The compose file in the repository expresses the same arrangement in a form you can keep in version control:
services:
tor-socks-proxy:
container_name: tor-socks-proxy
image: peterdavehello/tor-socks-proxy:latest
ports:
- "127.0.0.1:8853:53/udp"
- "127.0.0.1:9150:9150/tcp"
restart: unless-stoppedThat mapping is the reverse of the run command, 8853 on the host and 53 inside, so the two are not interchangeable. Following the README's run command exactly is the safer choice, since pointing a host resolver at the compose file's mapping would send plain DNS to the Tor DNS port.
The restart policy also differs, unless-stopped rather than always, which means a manual stop survives a reboot. For a container that exists to be started and stopped on demand, that is the more sensible of the two behaviours.
A new exit IP comes from restarting the container
Tor changes the circuit, and with it the address the outside world sees, every ten minutes by default. The README explains that you can renew the IP manually by restarting the container:
docker restart tor-socks-proxyThis is a blunt but effective tool. Restarting the process clears its state, so it bootstraps into the network again and comes up with a different exit path. For scripting, it means waiting for the client to be usable again before you rely on it.
That habit is also the reason the healthcheck exists and why the start period is long. A restarted container is briefly unhealthy, and the healthcheck is what tells an orchestrator the difference between starting and broken.
The README closes by pointing readers toward the Tor Project itself, asking them to set up bridge or exit nodes and to donate, which is a reasonable thing for a project whose own container deliberately refuses to do either.
Where this image stops being the right answer
The container does one job well and several jobs not at all, and the boundary is worth stating before you build on it.
It is not a relay or a bridge, by explicit design, so it cannot contribute capacity to the Tor network or serve users who need to bypass a blocking network. It is also not a general purpose web proxy: it exposes SOCKS5, and the README does not describe an HTTP proxy mode, authentication for connecting clients, or any access control beyond the address you bind the port to. If you need an authenticated proxy for several users, this is the wrong artifact.
The build policy is the other limitation. Taking tor and obfs4proxy from the Alpine edge repositories means the packages are the newest available, which is good for a client that should speak current protocol versions and bad for reproducibility. There is no pinned digest in the run command, the tag is latest, and the repository publishes no GitHub releases, so the exact contents of the image you ran last week and the one you run today can differ. The renovate configuration in the repository root suggests the base and dependencies are updated automatically.
The alternative is running Tor directly on the host, which the README itself points at by asking people to set up Tor relays or bridges. That route gives you the Tor package from your distribution, systemd unit files, a torrc you control, and no container layer between you and the process. The container buys isolation, a disposable configuration and one-command teardown, which is why it is a better fit for a CI job or a one-off scrape than for a long-lived service on a server you administer anyway.
Editorial conclusion
Adopt tor-socks-proxy when you want a disposable Tor SOCKS5 endpoint for one application, on a machine where you do not want to install Tor on the host and do not want to risk becoming a relay by accident. Do not adopt it if you need an authenticated proxy for untrusted users, an exit or bridge node, or reproducible builds, since the image tracks Alpine edge packages and no release tags are published. Verify first by running the healthcheck target through curl with the socks5-hostname option against your own container and confirming the container listens only on 127.0.0.1 before you change the published address.
Frequently asked questions
How do I run tor-socks-proxy in Docker?
Run docker run -d --restart=always --name tor-socks-proxy -p 127.0.0.1:9150:9150/tcp peterdavehello/tor-socks-proxy:latest. The SOCKS5 proxy then listens on 127.0.0.1 port 9150 on the host, and the image is also published as ghcr.io/peterdavehello/tor-socks-proxy.
Does tor-socks-proxy relay traffic or act as a Tor exit node?
No. The README states the container runs without Tor relay or exit node function enabled, so it is a client only. Anyone wanting to contribute capacity is pointed to the Tor Project's own relay guide and donation page.
How do I get DNS queries to go through Tor with tor-socks-proxy?
Publish the DNS port in addition to the SOCKS5 port, with an extra mapping of 127.0.0.1:53 to 8853 over UDP. The container exposes UDP 8853 for Tor DNS, and the image healthcheck verifies the SOCKS5 path against an onion address.
Official sources
Add this badge to your README
If you maintain this project, the badge below links readers to this analysis and shows its maintenance status from the daily GitHub snapshot. Paste the markdown into your README; add ?metric=license or ?metric=stars to the image URL for a different field.
[](https://hysenlabs.com/projects/peterdavehello-tor-socks-proxy)Was this useful?