Setting up a proxy on your Raspberry Pi

Pedro Pablo Fuentes Schuster
6 min readJan 19, 2020

All of this started the week before Thanksgiving, while many of you were making plans to spend time with your family, I was trying to have the best setup at home in case there was a problem with Zulily.com during our busiest season of the year, and also to be able to quickly glance over Grafana to do quick checks during those days on the overall health of the system.

I have a PC at home with multiple monitors, so instead of opening my work computer, I wanted to walk by my computer and check how things looked, so not much of a problem, I just needed to set up the VPN in my PC and have a browser with a Grafana playlist and done.

I gave it a try, but it ended being more complicated than I expected, the way that the VPN Client is configured to work is that all connections go through the VPN. I did not have a way to only use the VPN for specific domains, so if I wanted to play a game, browse, or anything else for personal purposes, I needed to turn off the VPN.

I know that there are other ways, like running a Virtual Machine on my computer, maybe a routing solution in Windows or potentially using Windows Subsystem for Linux, but I wanted to do something different and have some fun, so I bought a Raspberry Pi 4 to run the VPN and act as a proxy.

After installing Raspbian and having the basic setup done I got the VPN running, that part was easy, I tried multiple approaches, and at the end, the solution was a lot simpler than I expected.

The Solution

To use ssh to act as a socks proxy (ssh -D), set it up as a service, create a Proxy Auto-Configuration (PAC) file, serve it using Nginx and point the automatic proxy configuration on windows to that URL.

Step 1. Set up SSH as a Socks Proxy running as a Service

After reading and googling for some time, this article gave me the solution, and here is the step by step with some variations.

First, on your Raspberry Pi, we will use systemctl to create a unit file, adding “force” to the edit command will create a new file.

sudo systemctl edit --force --full socksproxy.service

Copy and paste the following code that sets up the proxy to listens to any IP address (0.0.0.0) on port 8000 and routes the traffic to your you Raspberry Pi (127.0.0.1):

[Unit]
Description=My Socks Proxy
Wants=network-online.target
After=network-online.target
[Service]
User=pi
WorkingDirectory=/home/pi
ExecStart=/usr/bin/ssh -o ServerAliveInterval=60 -nNT -D 0.0.0.0:8000 127.0.0.1
RestartSec=5
Restart=always
[Install]
WantedBy=graphical.target
  1. Be sure to change the user (pi), home folder (/home/pi) to match your user.
  2. The main difference with the solution in the article is that I added RestartSec=5 and Restart=always, this because the service will not work if this runs before the network is available, in my case, network-online.target did not work, I tried other options like network.target, but it did not work either, maybe because I was using WiFi and not ethernet, in the end, the simplest solution was to add the retry options.

Now we enable the unit

sudo systemctl enable socksproxy.service

We start the unit

sudo systemctl start socksproxy.service

And then we check the status

systemctl status socksproxy.service

If you later want to modify the service

sudo systemctl edit --full socksproxy.service

And once you are done, you don’t need to restart you can just do

sudo systemctl daemon-reload
sudo systemctl restart socksproxy.service

Step 2. Set up Nginx

Install Nginx in your Raspberry Pi

sudo apt-get install nginx

Find your Raspberry Pi IP using ip

ip -br -4 addr

You should get a response showing something like this

lo               UNKNOWN        127.0.0.1/8 
wlan0 UP 10.66.77.100/24

In this case, Raspberry Pi is connected to wi-fi, and you can find the IP on the wlan0 line, with the IP 10.66.77.100, if you are using ethernet, it would be on the eth0 line.

On your PC go to http://10.66.77.100, and you should see something like this

nginx welcome message

Step 3. Create your proxy.pac file

This turned out to be extremely simple, I used the Proxy Auto-Configuration (PAC) file article from Mozilla and is as simple as creating proxy.pac file to be served by Nginx and configure it properly.

The following is an example that assumes that:

  1. Your Raspberry Pi IP is 10.66.77.100, and the socks proxy is running in port 8000
  2. That you want to route traffic going to grafana.some.place.in.aws.com, in this case, a specific domain
  3. That you want to route all sub-domains of .company.internal, for example, git.company.internal or jira.tools.company.internal

Create the proxy.pac file

sudo nano /var/www/html/proxy.pac

Add the following code to it and save the file

function FindProxyForURL(url, host){
if(
dnsDomainIs(host, 'grafana.some.place.in.aws.com') ||
dnsDomainIs(host, '.company.internal')
){
return 'SOCKS 10.66.77.100:8000';
}
return 'DIRECT';
}

If you want to add more domains to be routed, keep adding

|| dnsDomainIs(host, ‘{domain}’)

And replace {domain} with the one that you would like to route through the proxy.

Also, to ensure that everything works properly, we need to edit the Nginx mime.types

sudo nano /etc/nginx/mime.types

and at the end of the file before the closing bracket } add the following line

application/x-ns-proxy-autoconfig     pac;

Then save and restart Nginx

sudo /etc/init.d/nginx restart

And finally, check that everything is working properly

curl -v http://10.66.77.100/proxy.pac

Remember to change 10.66.77.100 to your Raspberry Pi IP, or you can use 127.0.0.1, you should get something like

* Expire in 0 ms for 6 (transfer 0x5a0880)
* Trying 10.66.77.100...
* TCP_NODELAY set
* Expire in 200 ms for 4 (transfer 0x5a0880)
* Connected to 10.66.77.100 (10.66.77.100) port 80 (#0)
> GET /proxy.pac HTTP/1.1
> Host: 10.66.77.100
> User-Agent: curl/7.64.0
> Accept: */*
>
< HTTP/1.1 200 OK
< Server: nginx/1.14.2
< Date: Sun, 19 Jan 2020 03:39:03 GMT
< Content-Type: application/x-ns-proxy-autoconfig
< Content-Length: 221
< Last-Modified: Thu, 28 Nov 2019 07:39:25 GMT
< Connection: keep-alive
< ETag: "5ddf79ad-dd"
< Accept-Ranges: bytes
<
function FindProxyForURL(url, host){
if(
dnsDomainIs(host, 'grafana.some.place.in.aws.com') ||
dnsDomainIs(host, '.company.internal')
){
return 'SOCKS 10.66.77.100:8000';
}

return 'DIRECT';
}
* Connection #0 to host 10.66.77.100 left intact

So you should be able to see the code that you added to the file and also that the Content-Type is application/x-ns-proxy-autoconfig.

Step 4. Set up the proxy file in Windows

Search for proxy setting

Search for proxy settings

Open Proxy Settings and add the URL that points to your pac file, in this example http://10.66.77.100/proxy.pac and click save.

Proxy settings window

Step 5. Solve DNS problems

If you have challenges resolving internal company domains, you will see something like this on your PC.

This site can’t be reached error

An easy fix is to find out the IP address and add the domain to your Windows hosts file C:\Windows\system32\drivers\etc\hosts.

For example, if your company’s internal URL is jira.company.internal, go to your Raspberry Pi, and with your VPN connected, get that URL IP.

dig +short jira.company.internal

You will get the IP, for example, 10.10.1.6, copy that and now in your Windows machine go to C:\Windows\system32\drivers\etc\hosts and add the following line:

10.10.1.6 jira.company.internal

Repeat this for every domain.

Notes

I skipped the set up of the VPN, but for clarity, if your VPN is not running, the traffic will still be routed through your Raspberry Pi for the URLs defined in the proxy.pac file, what this means is that if you set a domain like google.com to go through the proxy, the traffic will be routed regardless of the status of your VPN.

--

--

Pedro Pablo Fuentes Schuster

I’m passionate about building great teams and ship game-changing products. http://pedrofuentes.com