I was a little bit disappointed to find out my church’s Cloudveil internet content filter does not work on linux. Fortunately there are other alternatives. Some of them are meant for being hosted as a server, but you can always set the server up on the client and then just forward to localhost. Below is a Claude Code summarization of a e2guardian setup on an intel iMac from 2013. I also revoked sudo access for the main user and setup automatic software updates (unattended-upgrades). This is for linux mint if you were wondering. Note that you could opt instead for an accountability app as long as you are using the x11 window server. I wish Accounable2You would make a version for Wayland. I have no idea if that is even possible since Wayland is so secure. For myself, I know I can bypass almost anything, and not having sudo access would ruin my life and sanity. By the way there is a bypass on the Cloudveil for windows filter that takes advantage of being on administrator account on Windows. If you open task manager and kill some cloud veil processes and then go to the directory where cloudveil-windows program files are, and copy them to another folder (or delete them) then the filter program will crash if certain important components are no longer in the program files directory. And if you did not delete them, you can just move them back and start the filter program again like nothing happened. I am telling you this not to suggest that you do it, but to suggest that you lock down administrator account and only use a regular windows account. This is important to do even without filters in mind for security reasons. Regular windows accounts can’t do as much damage to your computer as an admin account can; which means if a virus is downloaded by some unknowing user of your computer, it will not be able to run as admin, which greatly reduces what it can do.
There is a problem if you want to filter your Internet content but are tech savvy like myself. You can setup filters and all kinds of stuff, but it’s only a ssh and docker command away on a virtual private server, and you’re out. I think the only viable solution in this circumstance is accountability apps and just the responsibility of that much power. You can do anything, and nothing will stop you. You must stop yourself. And you might not even be able to do that.
The Basic Idea
The setup uses two proxies chained together. e2guardian sits in front and does all the thinking — checking sites against blocklists, enforcing safe search, deciding what gets through. It never talks to the internet directly, though. Everything it approves gets handed off to Squid, which handles the actual outbound connection.
For HTTPS traffic, e2guardian does full TLS interception. It intercepts the browser’s HTTPS connection, decrypts it, checks it against the rules, then either shows a block page or fetches the real content and re-encrypts it back to the browser with a certificate it generates on the fly. This is why the setup needs a locally trusted CA certificate — without it, every HTTPS site looks like a man-in-the-middle attack, because technically, it is one (just a friendly one).
Both e2guardian and Squid run as systemd services and start at boot, so once configured correctly, this is a “set and forget” layer.
Step 1: Configure the Core Filter
e2guardian’s config lives at /etc/e2guardian/e2guardian.conf, with Squid’s at /etc/squid/squid.conf. The actual blocklists — banned sites, banned SSL sites, banned URLs, banned phrases — live under /etc/e2guardian/lists/. For a serious deployment, load a combined blocklist; UT1 plus Steven Black’s list together gets you into the millions of entries, which is a solid baseline.
The MITM CA cert and key live in /etc/e2guardian/private/ — ca.pem is the public cert you’ll be distributing to every browser, ca.key stays put.
Step 2: Trust the CA — Everywhere, Separately
This is where most setups quietly fail. Every browser keeps its own certificate trust store, and none of them share with each other or with the OS. Trusting the CA in Firefox does nothing for Chrome. Trusting it system-wide (for curl/wget) does nothing for either browser.
For Firefox, the CA has to be imported into its NSS database, which lives inside the profile folder. Critically, Firefox must be fully closed before you touch this — it caches trust decisions while running and will happily clobber your changes on exit if you edit anything while it’s still open.
For Chrome on Linux, there’s an extra wrinkle: Chrome doesn’t use the system OpenSSL trust store at all. It keeps its own NSS database at ~/.pki/nssdb, which often doesn’t exist by default. If it’s missing, Chrome falls back to trusting only its built-in public root list — meaning every site the proxy intercepts, including totally unrelated ones, throws a certificate authority error. You have to create that database and import the CA into it manually.
For command-line tools like curl and wget, the standard update-ca-certificates flow handles it — drop the cert into /usr/local/share/ca-certificates/ and update the system store.
Step 3: Point Every Browser at the Proxy
Trusting the cert is only half the job — the browser also needs to actually route traffic through the proxy. Firefox manages this independently via its own proxy settings (network.proxy.type needs to be set to manual, with host/port filled in separately). Chrome on Linux, by contrast, doesn’t have its own proxy setting at all — it just reads whatever the system-level GNOME proxy setting is.
Miss either piece — proxy config or cert trust — and you get one of two failure modes: either the browser silently bypasses the filter entirely (wrong proxy setting), or every single HTTPS site throws a security warning (wrong or missing cert trust).
Step 4: Add Safe Search Enforcement
For forcing Google Safe Search, e2guardian supports connection-level rewriting through a file called sslsiteregexplist. This lets you silently redirect the upstream connection for a matched hostname to a different host — effectively a CNAME without touching DNS. The rule for Google looks like a regex match against the bare hostname, redirecting to forcesafesearch.google.com.
One trap to watch for: this file matches hostnames only, not full URLs — including a scheme prefix like https:// in the pattern means it will never match anything. Double-check any example rules you copy from vendor docs; they’re not always correct out of the box.
It’s tempting to also redirect gstatic.com the same way, but resist — that domain serves shared assets (fonts, reCAPTCHA, etc.) for a huge swath of unrelated sites, and rewriting it wholesale breaks things far outside the scope of image search.
Step 5: Verify It’s Actually Working
Don’t test with curl -k. Skipping cert validation hides exactly the kind of cert-trust failures you’re trying to catch, and doesn’t reflect what a real browser will experience. Instead, test with the real trust chain:
curl -x http://127.0.0.1:8080 –cacert /etc/e2guardian/private/ca.pem https://www.facebook.com
should return the block page with a cleanly validating cert, and a similar request to an allowed site should return real content. Live filtering decisions land in /var/log/e2guardian/access.log for confirmation.
Common Failure Modes (and What They Actually Mean)
A handful of issues tend to show up repeatedly in setups like this:
Proxy setting silently reverted or never applied — traffic bypasses the filter entirely with no errors. Symptom: filtering seems to do nothing.
CA imported but without trust flags — every HTTPS site throws a warning the moment the proxy is actually used.
CA regenerated without re-importing into browsers — this is the nastiest one. If the underlying CA cert gets regenerated (new fingerprint, possibly even a new CN), any browser still trusting the old cert will suddenly fail every HTTPS connection. Worse, HSTS-preloaded sites like Facebook give no click-through option when the cert doesn’t validate — it’s a hard block, not a warning. The fix is always the same: re-import the current ca.pem into whichever browser’s store has gone stale, after fully closing that browser.
Chrome missing its NSS database entirely — every intercepted site, including ones with nothing to do with your filtering policy, throws NET::ERR_CERT_AUTHORITY_INVALID until ~/.pki/nssdb is created and populated.
Known Non-Issues (Don’t Chase These)
A couple of things look alarming but aren’t actually bugs in the filter. Firefox’s background telemetry and push notification services will fail their TLS handshake through the MITM proxy — this is expected, since those specific endpoints pin their certificates and reject anything not signed by a public CA. It has no effect on normal browsing.
Similarly, if a specific site throws a Cloudflare error, check whether it reproduces on a direct connection outside the proxy first — it may be an issue with that site’s own tunnel setup, unrelated to your filter entirely.
Safe Search enforcement is also hard to verify with full certainty through automated means — confirming it fully requires either packet-level inspection or reading a JavaScript-rendered settings page. The practical answer is to fix the rewrite rule, reload e2guardian, and manually spot-check the “SafeSearch is locked by your network” indicator in an actual browser.
The Takeaway
The filtering logic itself — blocklists, safe search rewrites — is the least error-prone part of this stack. The actual failure points are almost always in the plumbing: mismatched certs, proxy settings that didn’t stick, or a browser with its own isolated trust store nobody remembered to populate. When something in this setup breaks, check the boring stuff first.
Leave a Reply