
Introduction
In an era where digital privacy is increasingly elusive, and the online world often feels like an open book, the pursuit of anonymity has become more vital than ever. Whether you’re an advocate for digital freedom, a journalist working on sensitive stories, or simply someone who values their online privacy, the concept of achieving true anonymity holds undeniable appeal.
Picture having a robust digital shield at your disposal—an online guardian that safeguards your internet activities, obscures your identity, and shields you from prying eyes. This is precisely what a Raspberry Pi Tor Proxy is designed to accomplish—a tool that, when properly configured, isolates your online presence from the vast landscape of the clearnet.
However, before we dive into the world of enhanced online privacy, it’s crucial to clarify one essential point: the Raspberry Pi Tor Proxy is not intended for personal use linked to your real-world identity. Instead, it is a means to achieve a level of online anonymity, ensuring that your virtual actions remain untraceable and unconnected to your personal life.
In this guide, we will explore the steps required to establish a Transparent Tor Proxy using a Raspberry Pi. This solution empowers you to navigate the online realm discreetly, concealing your digital footprints and protecting your online identity. Join us on this journey as we delve into the intricacies of setting up a Raspberry Pi Tor Proxy—a powerful tool for online anonymity.
Hardware
- raspberry-pi
- usb-ethernet adapter
- power supply
- micro SD card (16Gb at least)
- ethernet cables (2x)
Install OS
Download and install Ubuntu server ARM version: https://ubuntu.com/download/server/arm
Download the Raspberry-pi imager: https://www.raspberrypi.com/software/
Use the imager to install the OS on the SD card.
Once it’s installed put your public ssh key into /root/.ssh/authorized_keys
You can generate an ssh key with the following command:
user@pc:~$ ssh-keygen -b 4096 -f ~/.ssh/raspberry-pi
And uncomment this line in /etc/ssh/sshd_config to allow root login:
PermitRootLogin prohibit-password
Update Ubuntu
Boot the raspberry-pi and connect it to your LAN, then ssh to it:
user@PC:~$ ssh root@pi.local
Do a full upgrade:
root@pi:~# apt update && apt full-upgrade -y
root@pi:~# reboot -h now
Set name resolution
One of Tor’s biggest threats is DNS leaks. To counter this, we need to know who handles our DNS queries and, later, send them through Tor. Let’s disable systemd-resolved, which hides our DNS setup, and replace it with a system we control. Here are the key steps:
To prevent log errors related to naming issues on our Raspberry Pi, let’s start by ensuring it can always recognize its own name. We can do this by setting the hostname and specifying the name lookup like so:
root@pi:~# hostnamectl set-hostname portal
root@pi:~# echo "127.0.0.1 portal" | tee -a /etc/hosts
Now, we’ll turn off systemd-resolved and bring back the traditional resolv.conf file, which we’ll configure to point to our preferred DNS server (8.8.8.8 being Google’s).
root@pi:~# systemctl disable systemd-resolved
root@pi:~# rm /etc/resolv.conf
root@pi:~# echo "nameserver 8.8.8.8" | tee /etc/resolv.conf
Schema
Now this is the schema of the architecture we want:

All connections coming from eth1 will be redirected to the tor network (port 9050).
Dns requests (port 53) will be redirected to tor’s dns proxy (port 5353).
We also want to allow ssh connections (port 22) coming from eth0 for
administration purposes.
Configure the Network Adapters
We need to disable the automatic configuration coming from Cloud-Init and NetPlan:
root@pi:~# echo "network: {config: disabled}" | tee /etc/cloud/cloud.cfg.d/99-disable-network-config.cfg
Next, we’ll configure our network adapters, specifying eth0 for our public network (internet access) and eth1 for our private network, all within the NetPlan configuration:
root@pi:~# vim /etc/netplan/10-network.yaml
Then we’ll set this configuration:
network:
version: 2
renderer: networked
ethernets:
eth0:
dhcp4: true
nameservers:
addresses: [8.8.8.8,1.1.1.1]
eth1:
dhcp4: false
addresses: [172.16.0.1/24]
Apply it:
root@pi:~# netplan apply
Install the DHCP Server and Tor
Now we need a DHCP server on our private network, since our public network should already have one. And we also need to start Tor.
root@pi:~# apt install isc-dhcp-server tor -y
root@pi:~# systemctl enable tor
After installing, starting and enabling tor service, I realised that the service was not listening to the ports. After few searches I realised that apparmor was blocking it.
root@pi:~# mkdir /etc/systemd/system/tor@default.service.d/
root@pi:~# bash -c 'echo -e "[Service]\nAppArmorProfile=" > /etc/systemd/system/tor@default.service.d/override.conf'
root@pi:~# systemctl daemon-reload
root@pi:~# service tor restart
Configure and Enable the DHCP Server
Open the dhcp configuration file.
root@pi:~# vim /etc/dhcp/dhcpd.conf
Add these lines to establish a DHCP scope for the 172.16.0.0/24 network.
subnet 172.16.0.0 netmask 255.255.255.0 {
range 172.16.0.2 172.16.0.254;
option routers 172.16.0.1;
option domain-name-servers 172.16.0.1;
}
We defined the raspberry-pi’s IP address as the gateway and DNS server, to force all traffic through it.
Launch the DHCP server.
root@pi:~# systemctl restart isc-dhcp-server
Secure the Router with a Firewall
This step is crucial but often overlooked. We don’t mind traffic on our “trusted” network (eth1), but we want to block connections from the “untrusted” network (eth0). Luckily, we can easily set this up using Uncomplicated Firewall (UFW). Before we proceed, I recommend disabling IPv6 because most Tor relays don’t support it, and it makes us more vulnerable. To do this, let’s start by editing the UFW configuration.
root@pi:~# vim /etc/default/ufw
Change the line IPV6=yes to IPV6=no
Apply the change by running
root@pi:~# ufw reload
Now, let’s set up our firewall rules :
- Block all traffic as the default rule.
- Limit incoming connections to Tor, DNS and DHCP.
- Allow SSH on the public network for configuration purposes.
Simply use these UFW commands to configure it as desired:
root@pi:~# ufw allow in on eth0 to any port 22 comment "SSH Server"
root@pi:~# ufw allow in on eth1 to any port 67 proto udp comment "DHCP Server"
root@pi:~# ufw allow in on eth1 to any port 5353 comment "DNS Server"
root@pi:~# ufw allow in on eth1 to any port 9050 comment "Tor Proxy"
root@pi:~# ufw default deny
root@pi:~# ufw enable
If anything goes wrong, we need to be able to SSH into the Raspberry Pi to fix it. This line makes sure we can do that. We don’t want this port open on the Tor client side for obvious (or not) reasons, so we anable it to the eth0 interface.
Configure Tor to Act as a Proxy
We need to enable Tor proxy functionality.
root@pi:~# vim /etc/tor/torrc
Add the following lines to the end of the file.
VirtualAddrNetwork 10.192.0.0/10
AutomapHostsSuffixes .onion,.exit
AutomapHostsOnResolve 1
TransPort 172.16.0.1:9050
DNSPort 172.16.0.1:5353
The initial line sets up the virtual network Tor operates within, typically 10.192.0.0/10. This is the recommended setting by Tor experts, so it’s best not to alter it unless you’re well-versed in it. The following two lines are meant to catch DNS lookups for Tor network destinations. While they may not be critical for us, they tend to keep the client content. The last two lines are of utmost importance. They establish SOCKS and DNS proxies that link to the Tor network for our use.
Then restart the service.
root@pi:~# systemctl restart tor
If something goes wrong you can use this command to look at the logs.
root@pi:~# journalctl -f /usr/sbin/tor
Redirect All Incoming Traffic into Tor
Here’s the key moment: We want the Raspberry Pi to send all incoming traffic from the trusted network (eth0) through Tor. While UFW can assist with this, it doesn’t provide specific commands for it. So, we’re going to have some manual fun by editing the UFW configuration files. To make this happen, we’ll redirect the traffic before any filtering takes place, and we’ll do this by tweaking the “before” rules in UFW.
root@pi:~# vim /etc/ufw/before.rules
This configuration file is processed sequentially, starting from the top. Therefore, we should insert our configuration right at the top. Simply include these lines at the beginning of your file.
*nat
:PREROUTING ACCEPT [0:0]
:POSTROUTING ACCEPT [0:0]
:INPUT ACCEPT [0:0]
:OUTPUT ACCEPT [0:0]
-A PREROUTING -i eth1 -p udp -m udp --dport 53 -j REDIRECT --to-ports 5353
-A PREROUTING -i eth1 -p tcp -m tcp --tcp-flags FIN,SYN,RST,ACK SYN -j REDIRECT --to-ports 9050
COMMIT
Now, let’s quickly go over these lines.
*nat
The first line indicates we are doing NAT, or Network Address Translation. We are using NAT to manipulate the port numbers on our traffic.
:PREROUTING ACCEPT [0:0]
:POSTROUTING ACCEPT [0:0]
:INPUT ACCEPT [0:0]
:OUTPUT ACCEPT [0:0]
The next four lines are generic ACCEPT lines which mean we don’t want to filter anything. We want all traffic to pass.
-A PREROUTING -i eth1 -p udp -m udp –dport 53 -j REDIRECT –to-ports 5353
Our goal is to ensure secure handling of all DNS traffic through our device. This line intercepts any traffic using UDP port 53 (DNS) and redirects it to tor’s 5353. This ensures that even if an application tries to bypass our DNS server (like Windows Updates might), we capture and route it to our server.
-A PREROUTING -i eth1 -p tcp -m tcp –tcp-flags FIN,SYN,RST,ACK SYN -j REDIRECT –to-ports 9050
The final line is crucial. It’s what enables the transparent proxy to function. It takes any other TCP traffic and sends it to port 9050, where our Tor proxy is all set to handle it.
To apply these changes, simply run
root@pi:~# ufw reload
We have now completed our setup. The Raspberry Pi is now a router linked to Tor. The transparent proxy is active, ready for incoming traffic.
Test it
Testing the transparent proxy is simple. Connect a device to eth1, get an IP via DHCP, and go online.
Open a web browser and visit https://check.torproject.org. Hopefully, you’ll see a success message.

Additional Considerations
Now that we’ve completed the setup, there are a couple of special aspects worth noting. You might be intrigued by the idea of configuring your Raspberry Pi as a WiFi Access Point to provide Tor access. While it’s possible, I wouldn’t strongly recommend it. WiFi networks, by nature, are not confined, so you’d be exposing part of your network to others, somewhat reducing the effectiveness of the transparent proxy setup. However, I can understand scenarios where this could be beneficial. Think about devices like the Nintendo Switch, which lack physical network adapters; it could be handy to route them through Tor as well. If you’re interested in this, you can find numerous tutorials on configuring a WiFi Access Point on Ubuntu. Then, you’d just replace “eth1” in my instructions with the name of your wireless card.
Another consideration is captured portal systems, often used in hotels. These systems require you to authenticate through a web browser before gaining internet access. If you encounter such a setup, you’ll need to find a way for your Raspberry Pi to handle the authentication. The easiest approach is to install a graphical user interface like GNOME on the Raspberry Pi. This way, you can use a local browser on the Raspberry Pi to authenticate and then manage your other clients from there. Or you could just use lynx.