Privoxy Setup Guide
This guide walks through setting up Privoxy to provide network-wide ad and tracker filtering.
Architectural Strategy & Design Choices
- Avoiding Router-Based WPAD / Pi-Hosted PAC: Many home routers have restrictive, locked-down, or non-English firmware that prevents adding custom DHCP options (like Option 252) or local DNS overrides. Furthermore, if the Raspberry Pi is powered off, an internal web server hosting
wpad.datorproxy.pacbecomes unreachable, causing clients attempting to fetch the PAC file to fail entirely (ERR_PROXY_CONNECTION_FAILED). - Externally Hosted
.PACFile: To ensure client devices remain online even when the Pi goes down, a.PACfile can be hosted on an always-available external static host (such as GitHub Pages or a GitHub Gist). The browser loads the routing logic from the external source, attempts to route through Privoxy, hits a fast TCP timeout if the Pi is offline, and automatically falls back to aDIRECTinternet connection.
1. Install and Configure Privoxy
Installation
Run the following commands on your Raspberry Pi:
sudo apt update
sudo apt install -y privoxy
Configure Network Bindings
Open Privoxy’s main configuration file:
sudo nano /etc/privoxy/config
Locate the listen-address directives (around line 780). By default, Privoxy binds to IPv4 127.0.0.1:8118 and IPv6 [::1]:8118.
Replace both entries with a single IPv4 wildcard binding:
listen-address 0.0.0.0:8118
Note: Binding to a single dual-stack IPv6 wildcard
[::]:8118binding should tell the Linux dual-stack networking engine to listen on all IPv6 interfaces as well as all IPv4 interfaces simultaneously, avoiding port conflicts while providing full dual-stack coverage. But this fails overnight due to a companion cleanup service restarting privoxy with IPv4 forced.
Restart Privoxy to apply the binding change:
sudo systemctl restart privoxy
sudo systemctl enable privoxy
2. Streamline & Configure Auto-Updating Blocklists
Use privoxy-blocklist.sh to download AdBlock Plus lists and convert them into native Privoxy action files.
Install Dependencies & Script
sudo apt install -y wget sed grep
sudo wget https://raw.githubusercontent.com/Andrwe/privoxy-blocklist/master/privoxy-blocklist.sh -O /usr/local/bin/privoxy-blocklist.sh
sudo chmod +x /usr/local/bin/privoxy-blocklist.sh
Configure Filter Lists
Generate the default configuration file:
sudo /usr/local/bin/privoxy-blocklist.sh -q
Open the configuration file to customize the downloaded lists:
sudo nano /etc/privoxy-blocklist.conf
Find the URLS= array. Remove EasyList Germany (included by default by the script author) to save memory and processing overhead. Add comprehensive AdBlock Plus lists:
URLS=(
"https://easylist-downloads.adblockplus.org/easylist.txt"
"https://easylist-downloads.adblockplus.org/easyprivacy.txt"
"https://easylist-downloads.adblockplus.org/fanboy-annoyance.txt"
"https://raw.githubusercontent.com/uBlockOrigin/uAssets/master/filters/badware.txt"
)
Clean Up and Build Action Files
To remove old action files (such as easylistgermany.script.action) and generate the new rule set cleanly, reset the script database and execute a fresh run:
sudo /usr/local/bin/privoxy-blocklist.sh -r
sudo /usr/local/bin/privoxy-blocklist.sh
Restart Privoxy:
sudo systemctl restart privoxy
3. Automate Blocklist Updates with Cron
To keep filter rules current, schedule a weekly root cron job.
Why crontab -e?
Always use sudo crontab -e instead of directly editing /etc/crontab. Editing via crontab -e:
- Performs automatic syntax validation upon saving.
- Immediately signals the
crondaemon to reload the schedule without restarting the service. - Edits the root user’s individual cron spool file directly, avoiding syntax differences across system cron files.
Add Cron Entry
Open root’s crontab editor:
sudo crontab -e
Add a PATH definition at the top to ensure the script can be found, if it is not already present:
PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin
Add the following line at the bottom to schedule the script to run weekly at 3 AM on Sunday:
0 3 * * 0 /usr/local/bin/privoxy-blocklist.sh >/dev/null 2>&1
Output Redirection Syntax Explained
> /dev/null: Redirects standard output (stdout) to the null device, discarding routine log messages. You can replace/dev/nullwith a log file path if you want to keep logs.2>&1: Redirects standard error (stderr, file descriptor 2) to the same destination as standard output (stdout, file descriptor 1).- Combined Purpose: Discards all output and error logs, preventing
cronfrom attempting to send unnecessary local system emails or cluttering system logs.
4. Verify Script Execution & Privoxy Operation
Verify Script Execution
Confirm the update script created and registered the action files properly:
- Check generated action files:
ls -la /etc/privoxy/*.script.action
- Check Privoxy configuration integration:
grep "script.action" /etc/privoxy/config
Test Privoxy in the Browser
Set your browser proxy manually to your Pi’s local IP on port 8118 and test the connection:
- Internal Control Page: Navigate to http://config.privoxy.org/ (or
http://p.p/). If Privoxy is functioning, it intercepts this request and displays the “This is Privoxy” status page. - View Block Statistics & Active Rules: Visit http://config.privoxy.org/show-status. Under Actions Files, click View next to
easylist.script.actionto view the translated rules and confirmation of the build timestamp. - URL Rule Tester: Visit http://config.privoxy.org/show-url-info and submit an ad URL (e.g.,
http://pagead2.googlesyndication.com/pagead/js/adsbygoogle.js) to verify that Privoxy actively matches and blocks the domain.
5. Client Auto-Failover via External .PAC File
To ensure seamless internet connectivity when the Raspberry Pi is offline, host the .PAC file on an always-on external host (such as a secret GitHub Gist or GitHub Pages).
PAC File Content (proxy.pac)
Create a file named proxy.pac containing the following logic:
function FindProxyForURL(url, host) {
// 1. Direct connection for plain hostnames (e.g., http://router)
if (isPlainHostName(host)) {
return "DIRECT";
}
// 2. Direct connection for local IP subnets
if (
isInNet(host, "192.168.0.0", "255.255.0.0") ||
isInNet(host, "10.0.0.0", "255.0.0.0") ||
isInNet(host, "172.16.0.0", "255.240.0.0") ||
isInNet(host, "127.0.0.1", "255.255.255.255")
) {
return "DIRECT";
}
// 3. Send all traffic to Privoxy.
// If Privoxy is unreachable, immediately fall back to DIRECT internet.
return "PROXY 192.168.1.50:8118; DIRECT";
}
(Replace 192.168.1.50 with your Raspberry Pi’s actual static local IP).
Client Setup Instructions
Publish the file to your external host and copy the raw HTTPS URL (e.g., https://raw.githubusercontent.com/username/repository/main/proxy.pac).
- Windows: Go to Settings > Network & Internet > Proxy > Use setup script -> Set Script address to your external HTTPS URL.
- Android: Go to Settings > Wi-Fi > Select Network > Edit > Advanced Options > Proxy -> Change to Proxy Auto-Config -> Set PAC URL to your external HTTPS URL.
If you don’t want to use a PAC file, you can manually set the proxy in these locations. This will affect all browsers, but provide no failover.
Browser Extensions
Although there is some overlap, the browser extension uBlock Origin complements the proxy well. However, it is limited on non-Firefox browsers (e.g. Chrome, Edge).