Anonymous browsing on FreeBSD [incomplete]

Sometimes, there's a need to browse the web anonymously. It doesn't have to be for illegal purposes, it could just be you want to talk about your medical or even mental problems, sexual orientation, or maybe you want to "pentest" websites you don't own, just to make the web a better (more secure) place, by (anonymously!) communicating your findings to the owner ... I don't care – you just don't want to be identified. Here's what I found so far, investigating possibilities. Feel free to add additional info (I'd appreciate!)

1. Hiding your IP address

This is the most essential thing to do. You could always be identified by your IP address, at least your ISP will have logs making that possible. The canonical solution to this is Tor. Start with installing security/tor. If you install it on the same machine you will use for browsing the web, you won't need any configuration. In the default configuration, it will provide a SOCKS proxy listening only on the local loopback interface on port 9050.

2. Cleaning up HTTP

Unfortunately, HTTP (and other web standards like HTML/CSS/ECMAScript) have lots of "features" that allow server operators to recognize you. Without your IP address, it will be harder to actually know who you are, but correlating your activities, once one of them can be attributed to you, all others can as well. There's no perfect solution to this, but I recommend you install www/privoxy to make this less likely. Once installed, copy config and match-all.action from /usr/local/share/examples/privoxy to /usr/local/etc/privoxy.

In /usr/local/etc/privoxy/config, in the section about forward-socks*, add the following:
forward-socks5t / .
This will make sure, privoxy routes all traffic through Tor.

Privoxy comes with a somewhat sane default configuration. There's probably room for improvement (please add tips), but for now, there's ONE important thing: privoxy rewrites request and response content, and as most sites use encryption (https) nowadays (which is a good thing!), it has to "break" it to be able to access the clear text and rewrite anything. For this to work, it has to issue "fake" certificates on the fly, so it needs its own CA. Prepare it like this:
mkdir /usr/local/etc/privoxy/CA
cd /usr/local/etc/privoxy/CA
openssl req -new -x509 -extensions v3_ca -keyout cakey.pem -out cacert.crt -days 3650
# type whatever values you like here... take a note of the password you choose
ln -s /etc/ssl/cert.pem trustedCAs.pem
chown -R privoxy /usr/local/etc/privoxy/CA
chgrp -R privoxy /usr/local/etc/privoxy/CA
mkdir -p /usr/local/var/privoxy/certs
chown privoxy /usr/local/var/privoxy/certs
chgrp privoxy /usr/local/var/privoxy/certs
chmod 700 /usr/local/var/privoxy/certs
Then, edit /usr/local/etc/privoxy/config again, and uncomment ca-directory, ca-cert-file, ca-key-file, ca-password, certificate-directory and trusted-cas-file. The default values are all correct except for ca-password, you have to put your CA password you chose above there.

Finally, you must edit /usr/local/etc/privoxy/match-all.action. To enable HTTPS tampering, add +https-inspection \. I'd also recommend to rewrite the User-Agent header here to something common, using +hide-user-agent{<value>} \. E.g. I used the latest stable Chrome for Windows for now, so my whole config looks like this:
{ \
+change-x-forwarded-for{block} \
+client-header-tagger{css-requests} \
+client-header-tagger{image-requests} \
+client-header-tagger{range-requests} \
+hide-from-header{block} \
+set-image-blocker{pattern} \
+https-inspection \
+hide-user-agent{Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/95.0.4638.69 Safari/537.36} \

3. Configure your browser

I used www/chromium for my tests. I know, this certainly isn't the best choice for privacy. But, OTOH, considering fingerprinting, a rarely used minimal browser might "stick out" more easily. First thing to do, create a new profile, e.g. mkdir ~/.config/torium (got this idea from somewhere else: chromium using tor → torium. Yep, silly, but well…)

Then, create a startup script to run chromium in "anonymous" mode:
exec chrome \
    --proxy-server="" \
    --host-resolver-rules="MAP * -NOTFOUND" \

The host-resolver-rules is a precaution, it makes sure any DNS request chromium tries to do itself (not using the proxy) will just fail.

If you run your privoxy on a different host, you could use this instead:
exec chrome \
    --proxy-server="http://<yourprivoxyhost>:8118" \
    --host-resolver-rules="MAP * -NOTFOUND , EXCLUDE <yourprivoxyhost>" \
allowing chromium to resolve the name of your privoxy host itself, but nothing else.

Then, you have to import your privoxy fake CA's certificate, located in /usr/local/etc/privoxy/CA/cacert.crt, as a trusted CA, so chromium accepts the "tampered" responses. Open Settings, somewhere in the "security" area, I guess you will find it.

Finally, just disable any feature chromium offers. Especially disable Javascript. The possibilities to fingerprint your browser with Javascript are endless… it also makes sense to select a different default search engine (e.g. select duckduckgo).

4. Open issues, further thoughts

As an added benefit, you will get access to the "Darknet". Just look for the .onion virtual TLD. But browser fingerprinting remains an issue. I don't know any good solutions. Have a look here: – I have no idea how to prevent that (short of using a text browser knowing nothing about CSS). Just hoping site operators don't bother to do such stuff, cause almost any user on the web can be tracked/fingerprinted MUCH easier.
Additional non-tech OpSec advice: create a separate (secret and fake) identity for anonymous browsing. Continue using your normal browser for your day to day, non-sensitive activities. Never ever create a link between your fake/anon identity and your real one. This includes, don't share any (web)links. It should go without saying, but still, people were de-anonymized (aka doxxed) by doing stupid things like that in the past 🤡.

Additionally, if you're part of the "benevolent hacker" crowd: So you had some weird "oops" moment where some service misbehaved upon your input in your normal browser? Then just forget about it! Investigating the same "oops" anonymized won't help you, as the original "oops" might be logged (with your real IP address). You'll just be the "bad guy", no matter what your intentions are, and you'll be sued. If you want to improve web security, make sure to be as anonymous as possible from the very beginning.

That being said: Thanks for the likes so far. Still the "[Incomplete]" tag is there for a reason. Well, perfect anonymity isn't possible anways, but then, I assume there might be some tips to further improve it (maybe especially about what privoxy can do)? If you have any additional tips, please share, thanks!
Two more technical tips:

5. Clean up after privoxy's fake CA

From privoxy docs, I learned it never cleans up the fake certificates it issues. Of course, this makes sense according to Unix philosophy ;) but it means you have to do it yourself if you don't want these certificates to pile up forever. Here's a script to do it easily:

find ${CERTDIR} -type f -atime +${KEEPDAYS} -exec rm \{\} +
In this example, it would delete all certificates that weren't accessed during the last 14 days. It will only work reliably if your fs records access times (don't use the noatime mount option).

If the machine you're running privoxy on is up 24/7 or you use e.g. something like anacron, you can fully automate it, e.g. like this.
#minute    hour    mday    month    wday    who    command
0    3    *    *    *    root

6. Disable QUIC in chromium

QUIC is a new userspace transport layer protocol on top of UDP which replaces TCP with HTTP/3. When a proxy is configured, chromium should never use it, but I like to be sure. If it would be used (e.g. because of a bug in chromium), it would circumvent the proxy.

In chromium, enter chrome://flags in the URL bar. In the search box for flags, enter QUIC and then set it to disabled.
7. "Bonus": usage of "hidden services" other than web

If you followed this guide, you can also connect to "hidden services" (in the virtual .onion TLD) with your browser. But what if you want to use non-web "hidden services" (like e.g. Email, IRC, ...)?

If you're lucky, your client application already supports SOCKS proxies. Make sure at least SOCKS4A is supported. SOCKS5 is fine as well, the important thing is that hostname resolution is left to the proxy. (so, plain SOCKS4 won't work…)

If you're not so lucky, there's net/torsocks. It contains a wrapper script torsocks that preloads a library attempting to redirect any TCP traffic through your Tor socks proxy. So, just write e.g. torsocks ssh instead of ssh to login to a hidden (.onion) service with ssh. In case you don't run Tor on your local machine, edit /usr/local/etc/tor/torsocks.conf.

Some applications mysteriously fail with torsocks. If that's the case, there's one last straw: net/socat. You can always launch socat to offer a local TCP socket and redirect it through SOCKS like this:
socat TCP4-LISTEN:12345,reuseaddr,fork SOCKS4A:<hiddenservice>.onion:<port>,socksport=9050
Replace <hiddenservice> with the actual onion hostname of the service you want to connect to, and <port> with its port, e.g. 6667 for IRC. This assumes you run Tor locally (
Then, just connect to localhost:12345 (use any port you like, this is just an example) with your application to actually connect to the hidden service.

Important warning: Some application protocols reveil your real network address to the peer on the other side (e.g. SIP is doing that), some applications additionally use direct connections, sometimes via UDP. There's nothing Tor could do about that; using such a protocol, you won't be anonymous. Be sure you understand the application and the protocol before using it with Tor.
8. More hidden services with I2P

Tor isn't the only option for hosting hidden services. One of the largest alternatives is I2P. It does have similarities to Tor, but there are a few key differences, e.g. it's designed to tunnel (almost) any protocol (not just TCP), and it isn't designed for anonymous access to the "normal" internet (clearnet), although a few proxies exist doing that. Still, for anonymous browsing of the "clearnet", I recommend to stick with Tor.

But if you're interested in hidden services, you might like to add I2P to your setup. If you followed my guide above, it's easy to integrate seamlessly at least for websites.

I recommend installing security/i2pd. That's not the original (Java!) implementation, but a light-weight alternative implemented in C++ and works well for me. Once installed, edit /usr/local/etc/i2pd/i2pd.conf. You'll definitely want to review the bandwidth setting to somewhat match your connection and how much you want to be available for I2P traffic. By default, every I2P node takes part in the "mixing" and also forwards traffic for other users, you can configure a share of your bandwidth that should be available for that. Alternatively, you can disable it setting notransit = true, but only do that if you're short on bandwidth: forwarding is no security risk, everything is encrypted.

The daemon offers quite some services, you can disable any of them. For integrating with the privoxy/tor setup above, keep the SOCKS proxy enabled. You might also want to keep sam enabled, it's used by some applications specifically designed to tunnel their communications through I2P.

Now, the simple trick to integrate web browsing via I2P in your "anonymous" browser: edit your privoxy config (/usr/local/etc/privoxy/config) and add another forwarder line, so it looks for example like this (assuming you're using the default ports of tor and i2pd socks proxies):
forward-socks5t / .
forward-socks5t .i2p .
Order matters here. The first line will route everything through Tor, the second line sets an exception for .i2p domains and route them through I2P.

With that setting, you could start at e.g. http://reg.i2p/ or http://identiguy.i2p/ to discover domain names available inside the I2P network.
9. Privoxy improvements

I found a few tweaks to privoxy's configuration that I think make sense, so I'm documenting them here. Whether you want to apply them or not: you decide ;)

9.1 Add some standard filters to all requests

In /usr/local/etc/privoxy/match-all.action, you might want to add these lines:
+client-header-filter{privoxy-control} \
+client-header-filter{no-brotli-accepted} \
+client-header-filter{hide-tor-exit-notation} \
privoxy-control wipes all headers privoxy writes itself for "tagging" before the request goes out. I really wonder why this isn't in the default config. no-brotli-accepted removes br from the Accept-Encoding header, so servers won't send responses compressed with brotli. This makes sense because privoxy does not support brotli, so it wouldn't be able to rewrite these responses otherwise. hide-tor-exit-notation applies when you pick a specific Tor exit node by appending <node>.exit to the requested domain, it won't be visible in Referer etc. Probably a rarely used feature, but can't hurt ;)

9.2 Filter out Sec-Fetch-* headers

Chromium-based browsers send fetch metadata request headers. They are meant to give services more context for better security decisions. I'm not sure whether they hurt privacy per se, but at least, they make it obvious if you use a Chromium-based browser. You can wipe them from your requests as follows:

Create /usr/local/etc/privoxy/user.filter with this content:
CLIENT-HEADER-FILTER: no-sec-fetch Remove Sec-Fetch-* headers
Uncomment filterfile user.filter in /usr/local/etc/privoxy/config
Add this line to /usr/local/etc/privoxy/match-all.action
+client-header-filter{no-sec-fetch} \

9.3 Fake User-Agent for .onion and .i2p

In both Tor and I2P, there's a "typical" user-agent. For Tor, most ppl use the Tor Browser. For I2P, most people use the http proxy of the original implementation, which rewrites user-agent. To appear as "normal" as possible while browsing .onion or .i2p sites, we can fake both with privoxy:

Create /usr/local/etc/privoxy/user.action with this content:
{ +hide-user-agent{MYOB/6.66 (AN/ON)} }

{ +hide-user-agent{Mozilla/5.0 (Windows NT 10.0; rv:93.0) Gecko/20100101 Firefox/93.0} }
Uncomment actionsfile user.action in /usr/local/etc/privoxy/config