Originally published on https://blog.naba.run/posts/running-tor-proxy-with-docker/
Today I was testing dns-tor-proxy which required a SOCKS5 Tor proxy and realized I never ran a Tor service on my current machine. I use Tor browser almost daily for browsing websites I have absolutely no trust on, but not the standalone Tor proxy. In this article, I will try to set one up using the system package as well as inside a Docker container.
What is a Tor proxy?
A Tor proxy is a SOCKS5 proxy which routes your traffic through the Tor network. The Tor network ensures that any traffic originating from inside the network gets routed through atleast 3 random relays before exiting through the exit node.
It helps you to anonymize traffic, block trackers and, prevent surveillance amongst other benefits. If you are wondering who should use Tor, the answer is every person who cares about their privacy. You can read more about the architecture here.
Arch Linux
Tor is available in the Arch package repository and can be simply installed by:
# Install Tor
$ sudo pacman -S tor
...
# Start the service
$ sudo systemctl start tor
# Check whether the service is running
$ sudo netstat -tunlp | grep tor
tcp 0 0 127.0.0.1:9050 0.0.0.0:* LISTEN 3808529/tor
We see above that installing tor
through pacman
set up the systemd service as well. Jump to Using the proxy for the demo.
Debian/Ubuntu
The packages in the Debian ecosystem are often outdated. To get the latest version, one almost always needs to add third-party package repositories. I am not going into detail how to install Tor in that ecosystem, since there are a lot of distribution/version combinations. The steps are well detailed in the official Tor installation docs.
Docker
We will be building a very lightweight Docker image to reduce footprint.
Let's start with the Tor configuration,
SocksPort 0.0.0.0:9050
The above should get one started with the defaults. Feel free to change the port to whatever you like. The address being listened should be 0.0.0.0
as we would be accessing the server from outside the docker container.
# set alpine as the base image of the Dockerfile
FROM alpine:latest
# update the package repository and install Tor
RUN apk update && apk add tor
# Copy over the torrc created above and set the owner to `tor`
COPY torrc /etc/tor/torrc
RUN chown -R tor /etc/tor
# Set `tor` as the default user during the container runtime
USER tor
# Set `tor` as the entrypoint for the image
ENTRYPOINT ["tor"]
# Set the default container command
# This can be overridden later when running a container
CMD ["-f", "/etc/tor/torrc"]
Let's build the image now.
$ docker build -t palnabarun/tor .
Sending build context to Docker daemon 67.58kB
Step 1/6 : FROM alpine:latest
---> a24bb4013296
Step 2/6 : RUN apk update && apk add tor
---> Using cache
---> a5ea632ba987
Step 3/6 : COPY torrc /etc/tor/torrc
---> 5b351b9847bc
Step 4/6 : RUN chown -R tor /etc/tor
---> Running in 1f6950f03475
Removing intermediate container 1f6950f03475
---> 060ded5c532c
Step 5/6 : USER tor
---> Running in aa0553be76dc
Removing intermediate container aa0553be76dc
---> d763c1181285
Step 6/6 : ENTRYPOINT ["tor"]
---> Running in 97fd7f9ee693
Removing intermediate container 97fd7f9ee693
---> 13c889f5b018
Successfully built 13c889f5b018
Successfully tagged palnabarun/tor:latest
You might also be wondering what is the image size?
$ docker image ls | grep palnabarun/tor
palnabarun/tor latest 13c889f5b018 About a minute ago 21.1MB
The image is just a mere 21.1MB. Building docker images using Alpine Linux as base results in a very lightweight image.
Let's run the proxy.
$ docker run \
--rm \
--detach \
--name tor \
--publish 9050:9050 \ # change the port to whatever you put in the torrc
palnabarun/tor
aef03d84628b
$ docker ps | grep tor
aef03d84628b palnabarun/tor "tor" 31 seconds ago Up 30 seconds 0.0.0.0:9050->9050/tcp tor
After sometime the Tor proxy will succesfully establish a Tor circuit and it will be ready to use.
The Tor config and Dockerfile can be found here and there is a ready to consume image on Docker Hub
Using the proxy
Let's test whether the proxy is working correctly by some simple curl
calls.
The request below is not going through the proxy and hence would show your ISP provided IP address.
$ curl https://check.torproject.org/api/ip
{"IsTor":false,"IP":"49.30.XX.XX"}
Now, if we specify the Tor proxy when making the request, the IP address would be different.
$ curl --socks5 127.0.0.1:9050 https://check.torproject.org/api/ip
{"IsTor":true,"IP":"185.220.XXX.XXX"}
Also, notice the value of IsTor
in both the cases, the service running at check.torproject.org
knows whether the traffic was routed through the Tor network.
The very same proxy can be used in your browser by going to the Network Settings and changing to a manual proxy configuration. I, however, highly recommend to use the Tor browser if you just want to browse the internet through Tor.
Note: The IP addresses are partially redacted for privacy reasons.
If you are like me who cherishes reading RFCs, check out the following links
Top comments (3)
would it be possible to give the container a network for example tor-network and a second service like webtop is in the same network uses the tor proxy as gateway. And if so, could someone help me build something like that?
I recently created a docker container based on your code. It worked like charm!
How would one build several tor circuits inside the same container?
Or run many instances of the image, each container listening to another port?
Say, what would the ENTRYPOINT and CMD be?
Generally speaking, on debian I would create several torrc files e.g. torrc.1, torrc.2 and so forth, each of them with different SocksPorts (9060, 9062, etc) and according ControlPorts (9061, 9062, etc). It's worth mentioning that each torrc file has it's own DataDirectory e.g. /var/lib/tor1 for torrc.1 and the default user debian-tor owns those directories.
Not sure if you are still looking for a way of doing this, but I wanted something similar so I tried creating a
docker-compose.yaml
file containing:The you can do
docker-compose up --build
to start the containers.And test it:
P.S. @nabarun Thank you very much for this! :)