This post details how I set up my Raspberry Pi as an HTTP proxy through an SSH tunnel.
Disclaimer: I’m not an expert in privacy, security, networking, or anything else in this post… Proceed at your own risk. If you require privacy or security, I recommend following a different post.
These instructions are somewhat minimal and assume you’ve worked with a Raspberry Pi and SSH in the past.
Set up your Raspberry Pi
At a high level, you’ll need to flash an SD card, plug it in, set up your network, install updates (e.g.
sudo apt-get update && sudo apt-get upgrade).
Be sure to change your password (
Since we’ll be exposing the Pi to the internet, I set up SSH keys and disabled password access.
- See https://www.raspberrypi.org/documentation/remote-access/ssh/ for how to enable SSH (if you’re running headless, you might need to add an
sshfile directly to the SD card with another computer, see the bottom of that page). You’ve probably already done this if you ran the updates and configuration above.
- Setup SSH keys. Here are Pi-specific instructions.
- Disable password auth by editing
/etc/ssh/sshd_configand adding (or uncommenting) a
- Restart SSH with
sudo service ssh restart.
I’m running Raspbian. You may have to modify some instructions depending on your package manager, environment, etc. You could also do all of this on any network connected server, not just a Raspberry Pi.
Install a proxy (
The proxy will act as… the proxy running on the Pi. If you only want to use this as a SOCKS proxy, you can skip this step and not need any other software on the Pi. I haven’t tried this, but do a dynamic port forward rather than a direct one.
Install it with:
sudo apt-get install squid3
Then configure the
/etc/squid/squid.conf file. Make a backup first just in case:
sudo cp /etc/squid/squid.conf /etc/squid/squid.conf.backup
/etc/squid/squid.conf to have the following two lines:
acl localnet src 192.168.86.0/24 http_access allow localnet
This allows access to the proxy from your
localnet. Replace the IP address block with your local IP address block.
Then restart the
sudo service squid restart
squid listens on port
3128. You’ll need this when creating the tunnel later.
Configure your router
Proceed with caution. This step exposes your Pi to the internet. This may be more risk than you’re willing to take and you should evaluate if you would rather pay someone else (e.g. a cloud provider to run a VM for you…).
We’ll want to access our Raspberry Pi from outside our local network. So, we need to tell our router to send traffic on some port to the Pi. Each router will be different, but the goal is to create an entry to forward a port (let’s say
8888) to your Raspberry Pi port
22 (the default SSH port). Requests sent to your router on that port will be forwarded to the Pi. I’ll use
192.168.0.2 as the local IP of the Pi in this post.
You should also configure your router to give the Raspberry Pi a static IP address.
Find your public IP address
Visit a site like https://toolbox.googleapps.com/apps/browserinfo/ (or search [what is my ip]) to find your external IP address. Make a note of this, we’ll use it to SSH into our Pi. I’ll use
111.222.333.444 as an example in this post.
Open SSH tunnel connection.
The user/server to connect to is
firstname.lastname@example.org on port
8888 (whatever you set up on your router above).
You’ll also want to create a tunnel to send traffic from a local port (on your laptop) to the
squid proxy we started on the Pi above. Pick a port you want the tunnel to connect to on your laptop (let’s say
8080) and say to tunnel that to
[whatever your Pi's local IP is]:[the squid port]). In PuTTY, this is under
Connection > SSH > Tunnels in the left-hand menu.
On your laptop,
localhost:8080 will be sent through the SSH tunnel to
squid running on your Raspberry Pi (
192.168.0.2:3128). The SSH connection goes from your laptop to the port you exposed from your router (
8888) to port
22 of your Pi.
Save the connection settings so you can reuse it later.
Open the connection and leave it running in the background (you can disconnect when you’re done with the proxy).
Configure your laptop to use the proxy
On Windows, open your proxy settings and add an entry with Address
localhost and Port
8080 (or whatever port you configured with your SSH client). Here’s what it looks like on my computer:
You can also configure per-application proxy settings, but I haven’t tried this; I haven’t needed to.
Test it’s working
- Double-check the SSH connection is open.
- Double-check the proxy is enabled on your laptop.
- Visit a web page (or make some other web request). If it’s not working, double check all of the ports.
- Close the SSH connection, closing the tunnel. Web requests should stop working.
- Disable the proxy. Web requests should start working again.
Set up DNS
DNS lets you use an easy-to-remember name rather than IP address. But, the IP address might change at any time. So, you have two options:
- Ask your ISP for a static IP. Mine charges a one-time fee of $25 plus $19.99 per month (which I didn’t know about until my bill came and I disabled the static IP immediately…).
- Use dynamic DNS, where your Pi periodically notifies the DNS server what its IP address is (what I’m using today).
I’m using Google Domains for my domain. So, I followed their official instructions for setting up a subdomain for Dynamic DNS. There are many other providers of dynamic DNS services, but this one was easiest for me.
The Raspberry Pi needs to be configured to periodically ping the DNS server. I’m using
sudo apt-get install ddclient
This will take you through a series of dialogs to configure it, but it didn’t work well for me. Google Domains is natively supported by
ddclient, so I edited my config following the Google Domains docs:
ssl=yes use=web protocol=googledomains login=VGhpcyBpcyBub3QgdGhlIHJlYWwgbG9naW4u password=VGhpcyBhaW4ndCBpdC4= example.example.com
ddclient grabs the IP adress from a web service, rather than locally.
Then make sure the
ddclient service is started:
sudo service ddclient restart
You can make sure the IP address is being polled properly and authentication with the DNS service is working by running:
sudo ddclient -query sudo ddclient -daemon=0 -debug -verbose -noquiet
At this point, you should have a working HTTP proxy running on a Raspberry Pi (or other server) you can use through an SSH tunnel.
You might want to disable your router’s port forwarding rule if you don’t need the proxy right now. No need to leave it open if you’re not using it.
Some open questions I have:
- Android? iOS? I’ve seen some paid SSH clients that can open tunnels, but it seems cumbersome. I don’t need this, so I haven’t looked into it much.
- VPN? Why tunnel through SSH when I could set up a VPN (something like https://github.com/trailofbits/algo)? Could just start that up on some cloud provider VM and elimate a lot of security considerations with a bit of money.
- Dynamic port SOCKS proxy? Not run
squidat all? Haven’t tried it, haven’t needed it.
- Proxy DNS requests? Does DNS go through the proxy? If you’re trying to be completely private, the above is probably not enough.