Setting up a proxy on your Raspberry Pi
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
- Be sure to change the user (pi), home folder (/home/pi) to match your user.
- 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
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:
- Your Raspberry Pi IP is 10.66.77.100, and the socks proxy is running in port 8000
- That you want to route traffic going to grafana.some.place.in.aws.com, in this case, a specific domain
- 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
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.
Step 5. Solve DNS problems
If you have challenges resolving internal company domains, you will see something like this on your PC.
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.