View on GitHub

Raspberry Tor

Raspberry Pi used as a Tor router

Raspberry Tor

Raspberry Pi used as a Tor router


The purpose of Raspberry Tor is to securely and anonymously use the Internet. The Tor Project defends against network surveillance and traffic analysis. Tor joined with a Raspberry Pi provides a wireless router to ensure that all network traffic from a computer is automatically either blocked or routed through the Tor network.

This is a first but insufficient step to online anonymity.

Parts List


Start with a Raspberry Pi Lite with Wifi Access Point image. This is an image saved after following both the RPi Initial Setup Guide and the RPi Wifi Access Point Guide. If you do not have such an image, start with a Raspbian Lite image and follow the aforementioned guides before returning here.

  1. Write the image to the microSD.
  2. Connect to the Pi.
  3. Configure I2C.
  4. Real Time clock.
  5. Disable Internet date checking.
  6. Install macchanger.
  7. Add the Tor repository.
  8. Install Tor.
  9. Tor configuration.
  10. Iptables configuration.
  11. Create the log file.
  12. Set Tor to start at boot.
  13. Test the Raspberry Tor.
  14. Conclusion.



Write the image

Write the image to the MicroSD as described in the RPi Initial Setup Guide. Insert the MicroSD into the Pi.

Connect to the Pi

Connect to the pi using SSH over the network connection. Your wlan0 connection should be fully functional unless you are not on the same access point.

Configure I2C

Follow the Adafruit Guide.

Adding a real time clock

Tor network require accurate time keeping and, for anonymity, time keeping over the Internet should be disabled. Follow the PiHut Guide.

Disable Internet date checking

Having an accurate time is important for synchronized communications and for log filing. Linux, and most computers, use Network Time Protocol to check and validate the date/time. Remove the NTP package is an option, sudo apt-get remove ntp. NTP can always be easily reinstalled if it is later needed.

Install macchanger

Media Access Control (MAC) address is a hardware address that uniquely identifies each node of a network. Each of your network interfaces have a MAC address. Macchanger makes it easy to spoof your network node's MAC. See archlinux and debianadmin.

Note: See the discussion Which Wifi USB adapters

  • sudo apt-get install macchanger.
  • Choose Yes to the question Please specify whether macchanger should be set up to run automatically every time a network device is brought up or down. This gives a new MAC address whenever you attach an ethernet cable or reenable wifi. Change MAC automatically?.
  • Verify that the MAC is automaticaly changed by
    • checking your current MAC, ifconfig wlan0, make note of the HWaddr
    • take the interface down, sudo service network-manager stop
    • bring the interface up, sudo service network-manager start
    • check the new MAC, ifconfig wlan0

The MAC did not automatically change

If the MAC address did not automatically change, there are two options.

  • sudo nano /etc/init/macchanger.conf and add the following:
# macchanger - set MAC addresses
# Set the MAC addresses for the network interfaces.

description "change mac addresses"

start on starting network-manager

pre-start script
        /usr/bin/macchanger -e wlan0
        #/usr/bin/macchanger -e eth0
        #/usr/bin/macchanger -e wmaster0
        #/usr/bin/macchanger -e pan0
        #/usr/bin/logger wlan0 `/usr/bin/macchanger -s wlan0`
        #/usr/bin/logger eth0 `/usr/bin/macchanger -s eth0`
end script
  • Test it
  • If it still is not changing, /etc/init/network-manager.conf and add the following:
# network-manager - network connection manager
# The Network Manager daemon manages the system's network connections,
# automatically switching between the best available.

description "network connection manager"

start on (local-filesystems
          and started dbus)
stop on stopping dbus

expect fork
pre-start script
        /usr/bin/macchanger -e wlan0
        #/usr/bin/macchanger -e eth0
        #/usr/bin/macchanger -e wmaster0
        #/usr/bin/macchanger -e pan0
        #/usr/bin/logger wlan0 `/usr/bin/macchanger -s wlan0`
        #/usr/bin/logger eth0 `/usr/bin/macchanger -s eth0`
end script

Add the Tor repository

  1. Become root, sudo -i.
  2. Add the repository to the sources file, echo "deb release main" >> /etc/apt/sources.list. Replace release with the current stable release. In Jan2016, it is jessie.
  3. Add the repository key,
    • gpg --keyserver --recv 886DDD89
    • gpg --export A3C4F0F979CAA22CDBA8F512EE8CBC9E886DDD89 | apt-key add -
  4. apt-get update.
  5. Exit root, exit.

Install Tor

Installation is an easy one line command.

  • sudo apt-get install tor
  • Stop Tor, sudo service tor stop

Tor configuration

Configuration takes place in a number of service files. Let's start with Tor.

  • sudo nano /etc/tor/torrc
  • Scan over this configuration and try to understand as much as you can. Combine this with documents and FAQs from the Tor Project.
###############  Raspberry Tor Configuration ###
## dated 31JAN2016


# Transparent proxy port

# Explicit SOCKS port for local applications.
#SocksPort 9050

# Port that Tor will output 'info' level logs to.
Log notice file /var/log/tor/notices.log

# Have Tor run in the background
#Conflicts with systemd
#RunAsDaemon 1

# Only ever run as a client. Do not run as a relay or an exit.

# Ensure resolution of .onion and .exit domains happen through Tor.
AutomapHostsSuffixes .onion,.exit
AutomapHostsOnResolve 1

# Serve DNS responses

# Firewall will be blocking most outgoing ports
FascistFirewall 1

## End Raspberry Tor Configuration
  • Validate the configuration, tor --verify-config.

Some important configuration settings from the Tor manual are:

  • TransPort [address:]port|auto [isolation flags]
    • Open this port to listen for transparent proxy connections. Set this to 0 if you don’t want to allow transparent proxy connections. Set the port to "auto" to have Tor pick a port for you. This directive can be specified multiple times to bind to multiple addresses/ports. See SOCKSPort for an explanation of isolation flags.
    • TransPort requires OS support for transparent proxies, such as BSDs' pf or Linux’s IPTables. If you’re planning to use Tor as a transparent proxy for a network, you’ll want to examine and change VirtualAddrNetwork from the default setting. You’ll also want to set the TransListenAddress option for the network you’d like to proxy. (Default: 0)
  • VirtualAddrNetworkIPv4 Address/bits
    • When Tor needs to assign a virtual (unused) address because of a MAPADDRESS command from the controller or the AutomapHostsOnResolve feature, Tor picks an unassigned address from this range. (Defaults: and /10 respectively.)
    • When providing proxy server service to a network of computers using a tool like dns-proxy-tor, change the IPv4 network to "" or "" and change the IPv6 network to "[FC00]/7". The default VirtualAddrNetwork address ranges on a properly configured machine will route to the loopback or link-local interface. For local use, no change to the default VirtualAddrNetwork setting is needed.
  • DNSPort [address:]port|auto [isolation flags]
    • If non-zero, open this port to listen for UDP DNS requests, and resolve them anonymously. This port only handles A, AAAA, and PTR requests---it doesn’t handle arbitrary DNS request types. Set the port to "auto" to have Tor pick a port for you. This directive can be specified multiple times to bind to multiple addresses/ports. See SOCKSPort for an explanation of isolation flags. (Default: 0)
  • FascistFirewall 0|1
    • If 1, Tor will only create outgoing connections to ORs running on ports that your firewall allows (defaults to 80 and 443; see FirewallPorts). This will allow you to run Tor as a client behind a firewall with restrictive policies, but will not allow you to run as a server behind such a firewall. If you prefer more fine-grained control, use ReachableAddresses instead.

Iptables configuration

From earlier guides, the file /etc/iptables.test.rules /etc/iptables.test.rules was used to load the iptables rules. Here, a new file with some torrified rules added to the old rules will be used instead.

  • sudo nano /etc/iptables.tortest.rules

# Allow SSH to access point
-A PREROUTING -i wlan1 -p tcp --dport 22 -j REDIRECT --to-ports 22

# DNS routing
-A PREROUTING -i wlan1 -p udp --dport 53 -j REDIRECT --to-ports 53

# All other TCP traffic
-A PREROUTING -i wlan1 -p tcp --syn -j REDIRECT --to-ports 9040



# Allows all loopback (lo0) traffic and drop all traffic to 127/8 that
# doesn't use lo0
-A INPUT -i lo -j ACCEPT
-A INPUT ! -i lo -d -j REJECT

# Allows all local traffic from wlan1
# This may be tweaked to deny some traffic on wlan1
-A INPUT -i wlan1 -j ACCEPT

# Accepts all established inbound connections
-A INPUT -i wlan0 -m conntrack --ctstate ESTABLISHED,RELATED -j ACCEPT

# Prevent transproxy packet leak
-A OUTPUT -m conntrack --ctstate INVALID -j LOG --log-prefix "Transproxy ctstate leak blocked: " --log-uid
-A OUTPUT -m conntrack --ctstate INVALID -j DROP

# On wlan1
# Allow all outgoing traffic
# This may be tweaked to limit wlan1 traffic
-A OUTPUT -o wlan1 -j ACCEPT

# On wlan0
# Only allows outbound traffic to ports 80 and 443
# Also allow DNS traffic (needed for captive portal connection)
-A OUTPUT -o wlan0 -p tcp --dport 80 -j ACCEPT
-A OUTPUT -o wlan0 -p tcp --dport 443 -j ACCEPT
# Also allow DNS traffic (needed for captive portal connection)
# If needed, this rule may be dropped once connected to the portal
-A OUTPUT -o wlan0 -p udp --dport 53 -j ACCEPT

# Deny all other outbound traffic on wlan0
-A OUTPUT -o wlan0 -j REJECT

# Allows SSH connections
# The --dport number is the same as in /etc/ssh/sshd_config
-A INPUT -p tcp -m state --state NEW --dport 22 -j ACCEPT

# Limit SSH abuse
# The first rule records the IP address of each new attempt to access
# port 22 using the recent module. The second rule checks to see if that
# IP address has attempted to connect 4 or more times within the last
# 60 seconds, and if not then the packet is accepted.
-A INPUT -p tcp -m state --state NEW -m recent --dport 22 --set --name ssh --rsource
-A INPUT -p tcp -m state --state NEW -m recent --dport 22 ! --rcheck --seconds 60 --hitcount 4 --name ssh --rsource -j ACCEPT

# Allow Zeroconf connections. (Bonjour and Avahi)
-A INPUT -p udp -m state --state NEW --dport 5353 -j ACCEPT

# Allow ping
# note that blocking other types of icmp packets is considered a bad idea
# by some
#  remove -m icmp --icmp-type 8 from this line to allow all kinds of icmp:
-A INPUT -p icmp -m icmp --icmp-type 8 -j ACCEPT

# log iptables denied calls (access via 'dmesg' command)
-A INPUT -m limit --limit 5/min -j LOG --log-prefix "iptables denied: " --log-level 7

# Allow forwarded from wlan1 to permit NAT and Access Point
-A FORWARD -i wlan0 -o wlan1 -m state --state RELATED,ESTABLISHED -j ACCEPT
-A FORWARD -i wlan1 -o wlan0 -j ACCEPT

# Reject all other inbound - default deny unless explicitly allowed policy:

  • Become root, sudo -i.
  • Load the new rules, iptables-restore < /etc/iptables.tortest.rules.
  • Visually verify the new rules, iptables -t nat -S and iptables -S.
  • Save the new rules iptables-save > /etc/iptables.up.rules.
  • exit

Create the log file

  • Create the file, sudo touch /var/log/tor/notices.log.
  • Set the owner and permissions.
    • sudo chown debian-tor /var/log/tor/notices.log
    • sudo chmod 644 /var/log/tor/notices.log

Set Tor to start at boot

  • It Tor already enabled on boot, sudo systemctl is-enabled tor.service?
  • Enable Tor for boot start, sudo systemctl enable tor.service
  • Start Tor now, sudo service tor start

Test the Raspberry Tor

The final product is near. Let's do a little testing to make sure everything is performing as it should. (It is possible to tweak the iptables rules if needed.)

  • Start the pi, connect to it, and connect it to the network. Let the Using the WiFi Access Point with captured portal be your guide.
  • On the pi, links Should show Sorry. You are not using Tor.
  • From your connected device, use a standard browser to Should show Congratulations. This browser is configured to use Tor.
  • All connections from your connected device are routed through Tor.
  • The pi only allows outgoing connections to ports 80, 433, and 53.
  • Once connected to a captive portal, port 53 may be blocked.
    • Deny with sudo iptables -D OUTPUT -o wlan0 -p udp --dport 53 -j ACCEPT
    • Reallow with sudo iptables -A OUTPUT -o wlan0 -p udp --dport 53 -j ACCEPT

Some helpful commands for troubleshooting

  • sudo nano /etc/dhcp/dhcpd.conf
  • sudo service isc-dhcp-server restart
  • sudo nano /etc/hostapd/hostapd.conf
  • sudo service hostapd start
  • sudo service network-manager stop
  • sudo nmcli con up connection_name
  • sudo nano /etc/tor/torrc
  • sudo service tor status
  • sudo nano /etc/iptables.tortest.rules
  • sudo iptables-restore < /etc/iptables.tortest.rules
  • sudo iptables -t nat -S
  • sudo iptables -L
  • tail -F /var/log/tor/notices.log


Save the image file. After all that configuring it is good to make sure you can duplicate it.

The Tor Browser is recommended in addition to using the Raspberry Tor. It has a number of tweaks that improve anonymity. If you like this guide and using Tor, consider supporting the Tor Project. The easiest way to show your support is by setting up a relay. The Tor Project also accepts donations

After doing the research needed to make this guide work, I am planning on setting most of my servers as relays or bridges. I would really like to set up an exit node but that requires a bit more effort.