Free HTTP Proxy with a Raspberry Pi, an SSH Tunnel, and Dynamic DNS
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 (raspi-config
or passwd
).
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
ssh
file 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_config
and adding (or uncommenting) aPasswordAuthentication no
line. - 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 (squid3
)
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.
I’m using squid
.
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
Then edit /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 squid
service:
sudo service squid restart
By default, 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.
I’m using PuTTY on Windows. Use your preferred client. Be sure your SSH keys are configured properly so you can connect to your Pi (see the docs).
The user/server to connect to is pi@111.222.333.444
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 192.168.0.2:3128
(or [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 ddclient
:
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
I added use=web
so 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
Conclusion
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
squid
at 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.