Hardening Networking
Click to Expand Table of Contents
Since networks and systems vary, some adjustments may cause unexpected issues, especially around critical components like DNS or firewalls. Always review and test changes in a controlled environment before applying them broadly.
Understand the trade-offs and tailor the settings to your threat model and workflow. Take what’s useful, adapt as needed, and seek expert guidance for more advanced scenarios.
Introduction
Every setup is unique, feel free to adapt or skip sections based on your needs. Start with the basics and build up as you gain confidence. The goal is practical, tested hardening tailored to you.
Safe Browsing / Privacy Enhancing Habits
Adopt Encrypted DNS and HTTPS Everywhere
-
Configure your system and browsers to use DNS over HTTPS (DoH), DNS over TLS (DoT), or DNSCrypt to prevent DNS leakage. Use HTTPS-Only mode in browsers to encrypt all web traffic. Prefer browsers with strong privacy defaults or add recommended extensions.
-
Disable browser "remember password" and autofill features, clear cookies and site data upon exit, and carefully vet suspicious URLs with tools like VirusTotal.
Limit Account Linking and Use Unique Credentials
- Create separate accounts with unique passwords instead of signing in with Google, Facebook, or similar services to limit broad data exposure from compromises.
Use Metadata Cleaning Tools
-
Many files like images, PDFs, and office documents contain hidden metadata information such as location data, device details, and more that can reveal your identity or other sensitive information when you share files publicly.
-
To protect your privacy, always sanitize files by removing this metadata before sharing. Tools like mat2 are designed to strip metadata from a wide range of media files efficiently. (
pkgs.mat2). You just typemat2 swappy-2025.pngfor example and there will then be a newmat2 swappy-2025.cleaned.pngthat can safely be shared.
Use Anonymous File-Sharing Tools
- For sensitive transfers, consiter tools like
OnionShare that provide anonymity
and security.(
pkgs.onionshare)
Avoid Scanning Random QR Codes Without Verification
- Use QR code scanner apps that check for malicious content before loading links.
Understand Your Threat Model
- Apply these basics universally, but tailor advanced hardening according to your unique environment, connectivity needs, and risk profile.
Delete cookies and site data when the browser is closed. (security not usability).
Use Strong, Unique Passwords and a Password Manager
-
Avoid reused passwords by using reliable password managers like KeePassXC or Bitwarden, both available on NixOS. Pair this with enabling two-factor authentication (2FA) wherever possible.
-
It's advisable to only use the desktop version and not the browser extension for a number of reasons. One is that you can store your passwords completely offline and have complete ownership of them.
environment.systemPackages = [
pkgs.keepassxc
pkgs.kpcli # KeePass CLI
# OR
pkgs.bitwarden-desktop
pkgs.bitwarden-cli
];
With KeePassXC, you can require 3 different authentication methods at the same time. You can choose a password, a keyfile, and a security key where it won't open unless all 3 are present giving you additional security. All 3 might not be necessary but it's possible. It's also easy to migrate to KeePassXC, you can import your vault from many different managers.
KeepassXC also makes it easy to keep your complete password database offline which can significantly reduce the risk of a breach.
With Bitwarden, to enable 2 factor authentication, you need to log in with your master password through the web interface.
Why Follow These Basics?
These recommended steps help protect your privacy and security while maintaining usability and minimizing system interruptions. They catch common threats like network eavesdropping, password reuse, fingerprinting, and data leakage, providing a solid foundation to build on.
A vast majority of secure and privacy-focused browsers available for NixOS are based on Firefox. Chromium derivatives like Ungoogled Chromium and Brave do exist in Nixpkgs, but are less recommended by privacy advocates.
❗ NOTE: Firefox does lack some security features available in Chrome and sandbox escapes in Linux are relatively easy. People such as madaidan say to never use Linux or Firefox period when you're worried about security and privacy. I personally don't care how good Chrome's security features are when Google itself is an adds company. It's also scary how much you actually have to turn off to make it somewhat secure and private. Chrome also just paid a huge settlement for selling peoples information that had already opted out.
This GrapheneOS article, breaks down why they use Chromium-based browsers and specifically mentions that it's not recommended to use Firefox, especially on Linux because of the weak sandboxing.
As a Chromium-based browser, Brave has been growing on me. Brave uses randomization rather than standardization for fingerprinting protection. If you run Cover Your Tracks with Brave, it will show a randomized fingerprint.
✔️ Click To Expand United States Patriot Act Overview
Section 215 USA Patriot Act permits the collection of "Tangible Things" or "Business Records", e.g., your phone records, medical records, etc. for an investigation to obtain foreign intelligence information. If it does relate to a US person it must be relevant to preventing terrorism or espionage, and not be based solely on activities protected by the first amendment. "Relevant" is the key word here and it is at the governments discretion meaning they sweep everything and sift it later. Criticized for violating American citizens Fourth Amendment protections against warrantless search and seizure and proven to be ineffective.
What is "normal" and allowed today might be suppressed tomorrow, look at the UK Online Safety Act purported to protect children, accused of banning privacy. This is because the only way to verify age is to make everyone submit KYC with their drivers license or ID, completely taking away any anonymity of adults and children alike.
Also see BBC 4chan refuses to pay fine
The mere existence of a surveillance state breeds fear and conformity and stifles free expression.--The Intercept
There are much more scary examples in Privacy, The new Oil
Choosing Secure/Private Browsers and Search Engines
On a hardened Linux system, the browser is most often the weakest link exposed to the internet, and so security, privacy, and anti-tracking features of browsers are now as important, or even more important than platform-level protections.
Fingerprinting
There are two main approaches to obfuscating your fingerprint:
-
Standardization: Make browsers standardized and therefore have the same fingerprint to blend into a crowd. This is what Tor and Mullvad Browser do. Best for anonymity; increases the crowd you blend into, but may decrease usability (site breakage, CAPTCHAs); adversaries may still find subtle differences.
-
Randomization: Randomize fingerprint metrics so it's not directly linkable to you. Brave has this feature, if you run coveryourtracks with Brave you will get a result of "your browser has a randomized fingerprint". This is good for privacy but may be detectable by advanced scripts.
Firefox
My understanding here is evolving, Firefox on Linux may be very privacy friendly but is not necessarily a secure browser.
Firefox's defaults are not privacy respecting or secure but allows a high level of customization to make it so. Firefox will be patched with security fixes sooner than any fork, and some forks are slow to apply the updates leaving a vulnerability open longer to exploit.
The Tor Uplift Project was a collaboration between the Tor Project and Mozilla to integrate key privacy and anti-fingerprinting features from the Tor Browser into Firefox. This enables us to enable/disable a few settings and remove the need for most add-ons.
If you use Firefox's ETP, RFP, and other protections provided by the ghacks or Arkenfox scripts alongside uBlock configured to use dynamic filtering you can accomplish what it used to take 10 extensions to do.
With uBlock you can Disable JavaScript which functions similar to NoScript,
enable numerous blocklists and more.
To enable Enhanced Tracking Protection and FPP, go to
Settings -> Privacy & Security -> Enhanced Tracking Protection -> Custom. If
it causes breakage, while on the broken site, click the sheild next to the
search bar. From there you can turn off ETP for just that site.
Once you select Custom, you'll see that among the options is to block
Known fingerprinters as well as Suspected fingerprinters. The "Known
Fingerprinters" protection works by blocking scripts listed in
Disconnect's fingerprinting list
For most users they suggest using the above FPP to avoid breakage. To enable
RFP, go to about:config and set privacy.resistFingerprinting to true.
Tor Browser
❗ NOTE: Tor is not the most secure browser, anonymity and security can often be at odds with each other. Having the exact same browser as many other people isn't the best security practice, but it is great for anonymity. Tor is also based on Firefox Esr, which only receives patches for vulnerabilities considered Critical or High which can be taken advantage of.
Tor is a modified version of Firefox specifically designed for use with Tor.
Tor routes your internet traffic through a global volunteer-operated network, masking your IP address and activities from local observers, ISPs, websites, and surveillance systems. This helps you protect personal information and maintain anonymity when browsing, communicating, or using online services.
Adding browser plugins to Tor can de-anonymize you, don't do it. Tor is already built with the necessary plugins and privacy protecting rules, so adding more is unnecessary and actually dangerous for your anonymity.
A Tor exit node can easily see your traffic, and if you're not using HTTPS then
it may be able to modify that traffic. Only use HTTPS when browsing the clear
net with Tor, this doesn't apply to onion services (.onion) as the traffic
stays inside the Tor network all the way to the destination.
You can visit both the clear web and .onion sites on Tor. Whenever possible
you should utilize Onion Services (.onion addresses) so communications and web
browsing stay within the Tor network. .onion URLS form a tunnel that is
end-to-end encrypted using a random rendezvous point and incorporating
perfect forward secrecy (PFS).
Bridges are only necessary in countries that don't allow people to use Tor. Using Bridges when they aren't needed takes resources away from people in oppressive regimes that need, only use them if necessary. Read the guides, and use Tails OS, or Whonix when it really matters.
You will see a lot of conflicting information about using Tor with a VPN. If you are in an area that blocks access to Tor or it is dangerous to use Tor, by all means use a trusted VPN.
TorPlusVPN
Learn about Tor
I recommend starting with Privacy Guides In Praise of Tor and then reading their Tor Overview they have been the most informative resources I've come across yet.
The Electronic Frontier Foundation sponsors and helps fund Tor and so does the United States Government.
If you are fortunate to live outside of oppressive regimes with extreme censorship, using Tor for every day, mundane activities is likely safe and won’t put you on any harmful “list.” Even if it did, you'd be in good company—these lists mostly contain great people working tirelessly to defend human rights and online privacy worldwide.
By using Tor regularly for ordinary browsing, you help strengthen the network, making it more robust and anonymous for everyone. This collective support makes staying private easier for activists, journalists, and anyone facing online surveillance or censorship. The writer of the PrivacyGuides article mentions using Tor when he needs to access Google Maps to protect his privacy
So, consider embracing Tor not only for sensitive browsing but also for daily routine tasks. Every user adds valuable noise to the network, helping protect privacy and freedom for all.
Tor is at risk, and needs our help. Despite its strength and history, Tor isn't safe from the same attacks oppressive regimes and misinformed legislators direct at encryption and many other privacy-enhancing technologies.--How to Support Tor
Mullvad-Browser
Rather than try to tweak a browser into fingerprinting submission, I recommend using either Tor or Mullvad-Browser when fingerprintability is the highest issue. Both Tor and Mullvad-Browser were designed specifically for this purpose and you likely won't get as much out of tweaking another browser.
Mullvad-Browser is free and open-source and was developed by the Tor Project in collaboration with Mullvad VPN.(Another Firefox Derivative). It is also the top recommended browser from PrivacyGuides.
It is the Tor Browser without the Tor Network, allowing you to use the privacy features Tor created along with a VPN if you so choose.
- Mullvad-Browser, is in Nixpkgs as:
pkgs.mullvad-browser
LibreWolf
LibreWolf is an open-source fork of Firefox with a strong focus on privacy, security, and user freedom. LibreWolf enables always HTTPS, includes uBlockOrigin, and only includes privacy focused search engines by default such as:
SearXNG an open-source, privacy-respecting metasearch engine that aggregates
results from various search services, such as Google, DuckDuckGo, etc without
tracking you or profiling your searches. You can add SearXNG to firefox by going
to about:preferences#search and at the bottom click Add, URL will be
https://searx.be/search?q=%s.
❗️ NOTE: The above searx is the default and doesn't give many relevant results. To get relevant results find a public instance with a good rating from your area and add the
search?q=%sto the end of it. For example, I'm usinghttps://priv.au/search?q=%s. This gives better results than DDG in my opinion.
Searx is a bit different, you can choose which search engine you want for your
current search with !ddg search term to use duckduckgo for example.
Example LibreWolf config implementing many of the STIG recommendations:
✔️ Click to expand LibreWolf Example
# librewolf.nix
{pkgs, lib, config, ...}: let
cfg = config.custom.librewolf;
in {
options.custom.librewolf = {
enable = lib.mkOption {
type = lib.types.bool;
default = true;
description = "Enable the LibreWolf Module";
};
};
config = lib.mkIf cfg.enable {
programs.librewolf = {
enable = true;
policies = {
# A bit annoying
DontCheckDefaultBrowser = true;
# Pocket is insecure according to DoD
DisablePocket = true;
# No imperative updates
DisableAppUpdate = true;
};
settings = {
# // SV-16925 - DTBF030
"security.enable_tls" = true;
# // SV-16925 - DTBF030
"security.tls.version.min" = 2;
# // SV-16925 - DTBF030
"security.tls.version.max" = 4;
# // SV-111841 - DTBF210
"privacy.trackingprotection.fingerprinting.enabled" = true;
# // V-252881 - Retaining Data Upon Shutdown
"browser.sessionstore.privacy_level" = 0;
# // SV-251573 - Customizing the New Tab Page
"browser.newtabpage.activity-stream.enabled" = false;
"browser.newtabpage.activity-stream.feeds.section.topstories" = false;
"browser.newtabpage.activity-stream.showSponsored" = false;
"browser.newtabpage.activity-stream.feeds.snippets" = false;
# // V-251580 - Disabling Feedback Reporting
"browser.chrome.toolbar_tips" = false;
"browser.selfsupport.url" = "";
"extensions.abuseReport.enabled" = false;
"extensions.abuseReport.url" = "";
# // V-251558 - Controlling Data Submission
"datareporting.policy.dataSubmissionEnabled" = false;
"datareporting.healthreport.uploadEnabled" = false;
"datareporting.policy.firstRunURL" = "";
"datareporting.policy.notifications.firstRunURL" = "";
"datareporting.policy.requiredURL" = "";
# // V-252909 - Disabling Firefox Studies
"app.shield.optoutstudies.enabled" = false;
"app.normandy.enabled" = false;
"app.normandy.api_url" = "";
# // V-252908 - Disabling Pocket
"extensions.pocket.enabled" = false;
# // V-251555 - Preventing Improper Script Execution
"dom.disable_window_flip" = true;
# // V-251554 - Restricting Window Movement and Resizing
"dom.disable_window_move_resize" = true;
# // V-251551 - Disabling Form Fill Assistance
"browser.formfill.enable" = false;
# // V-251550 - Blocking Unauthorized MIME Types
"plugin.disable_full_page_plugin_for_types" = "application/pdf,application/fdf,application/xfdf,application/lso,application/lss,application/iqy,application/rqy,application/lsl,application/xlk,application/xls,application/xlt,application/pot,application/pps,application/ppt,application/dos,application/dot,application/wks,application/bat,application/ps,application/eps,application/wch,application/wcm,application/wb1,application/wb3,application/rtf,application/doc,application/mdb,application/mde,application/wbk,application/ad,application/adp";
};
};
xdg.desktopEntries.librewolf = {
name = "LibreWolf";
exec = "${pkgs.librewolf}/bin/librewolf";
};
xdg.mimeApps = {
enable = true;
defaultApplications = {
"text/html" = "librewolf.desktop";
"x-scheme-handler/http" = "librewolf.desktop";
"x-scheme-handler/https" = "librewolf.desktop";
"x-scheme-handler/about" = "librewolf.desktop";
"x-scheme-handler/unknown" = "librewolf.desktop";
};
};
};
}
And enable it in your home.nix or equivalent with:
# home.nix
custom.librewolf.enable = true;
The xdg settings at the end make LibreWolf the defaults for what is listed.
Thanks to JosefKatic for putting the above STIG settings in NixOS format.
Also, go to accounts.firefox and turn off "Allow Mozilla accounts to send technical and interaction data to Mozilla". Also set 2-fa in Security Settings
I always set Max Protection for DNS over HTTPS and personally set a custom
resolver to https://dns.quad9.net/dns-query
- Mullvad is also a good option: Mullvad no-logging-data-policy
Firefox Relay is a pretty cool privacy tool too, it gives you temporary email and phone number aliases so you don't have to give out your real ones. There is an autofill option available also, but you can just click on the Relay button and generate a new alias and use it like your normal email.
✔️ Alternative LibreWolf Configuration utilizing Arkenfox
{
pkgs,
lib,
config,
...
}: let
cfg = config.custom.librewolf;
in {
options.custom.librewolf = {
enable = lib.mkOption {
type = lib.types.bool;
default = true;
description = "Enable the LibreWolf Module";
};
};
config = lib.mkIf cfg.enable {
programs.librewolf = {
enable = true;
policies = {
DontCheckDefaultBrowser = true;
DisablePocket = true;
DisableAppUpdate = true;
};
profiles.my-default = {
isDefault = true;
name = "Default Profile";
extraConfig = ''
${builtins.readFile ./user.js}
"general.autoScroll" = true;
"sidebar.verticalTabs" = true;
'';
settings = {
};
};
};
xdg.desktopEntries.librewolf = {
name = "LibreWolf";
exec = "${pkgs.librewolf}/bin/librewolf";
};
xdg.mimeApps = {
enable = true;
defaultApplications = {
"text/html" = "librewolf.desktop";
"x-scheme-handler/http" = "librewolf.desktop";
"x-scheme-handler/https" = "librewolf.desktop";
"x-scheme-handler/about" = "librewolf.desktop";
"x-scheme-handler/unknown" = "librewolf.desktop";
};
};
};
}
Download the
Arkenfox user.js and
review it making sure that you agree with the settings. If you do, place it in
the same directory as your librewolf.nix.
Read the Arkenfox Wiki
The user.js is full of comments and information, read it and adjust it for
your needs. The following enables RFP fingerprint protection:
***/ user.js ***/
user_pref("privacy.resistFingerprinting", true); // [FF41+]
user_pref("privacy.resistFingerprinting.pbmode", true); // [FF114+]
As you learn more, you can get more strict if you so choose.
Rebuild, launch LibreWolf, and check your ~/.librewolf/my-default/user.js. It
should match the Arkenfox settings. Initially, only the user.js will be
listed, as you run LibreWolf other profile files and folders are created
dynamically.
In LibreWolf type Ctrl + Shift + J and look for any errors.
Type about:config into the address bar and search a few of the settings that
Arkenfox changes, do they match?
The user.js is read in order, if there are 2 of the same setting, the last
one will be applied. Adding overrides to the settings attribute above places the
changes at the beginning of the user.js which isn't what we want. Placing
them after the ${builtins.readFile ./user.js} in extraConfig amends them to
the end of the user.js allowing us to override the defaults.
The process is the same with Firefox but since Arkenfox strongly recommends Ublock Origin and it is built into LibreWolf it makes sense to use the browser with the stronger defaults.
❗ NOTE: There is a home-manager module called
arkenfox-nixosthat is supposed to make updates easier but IMO the documentation leaves you guessing how to use it. As updates come in to Firefox/LibreWolf some of the settings become unnecessary so it's important to keep an eye on both Firefox and Arkenfox updates. Which both have RSS feeds that will alert you upon changes.
I personally use Feeder as my open-source RSS feed reader, available in most app stores including F-Droid. It is listed on PrivacyTools.
Fingerprint Testing
You can test your browser to see how well you are protected from tracking and fingerprinting at Cover Your Tracks.
Also check out, Am I Unique
⚠️ WARNING: Don't put too much weight into the results as people often check their fingerprint, change one metric and check it again over and over skewing the results. It is helpful for knowing the fingerprint values that trackers track.
✔️ Click to Expand Script to wipe cache and generate new `machine-id`
-
The following example is adapted from Firejail All About Tor section, adapted for NixOS.
Save the following script as cleanup.sh, change Your-User to your username:
#!/bin/sh -e
USER="Your-User"
HOME_DIR="/home/$USER"
# clear user cache directly as root
sudo -u "$USER" rm -fr "$HOME_DIR/.cache"
# generate a new machine-id
rm -f /var/lib/machine-id
dbus-uuidgen > /var/lib/machine-id
cp /var/lib/machine-id /etc/machine-id
chmod 444 /etc/machine-id
exit 0
The ~/.cache directory is where most programs store runtime information:
webpages you visited, torrent trackers you connected to, and deleted emails.
It's a good idea to remove them at shutdown. --Firejail all-about-tor
Check /etc/machine-id & ~/.cache before running the script:
cat /etc/machine-id
# Output
0b46feb27a20469da0ee62baaeb51c5c
ls ~/.cache
chmod +x cleanup.sh
sudo ./cleanup.sh
Recheck your machine-id and ~/.cache directories, you should have a newly
generated machine-id and minimal files in the ~/.cache directory. The
Firejail example shows a systemd unit that runs the above script at every
shutdown but that may be overkill, I suggest running it occasionally to make it
harder for sites to link your machine-id to you.
Privacy protection doesn't need to be perfect to make a difference. The best protection against tracking and fingerprinting available is to use Tor. Many add-ons are redundant, do some research and avoid using an add-on for something that can be accomplished with built-in settings.
There are more hardening parameters that can be set but this should be a good starting point for a hardened version of LibreWolf. When testing with Cover your tracks, customized LibreWolf tested as having stronger tracking protection than default Mullvad-Browser and NoScript significantly cuts down the data available for fingerprinting by disabling JavaScript.
- The Garuda Privacy-Guide has good tips and recommendations for browser add-ons.
Virtual Private Networks (VPNs)
A VPN (Virtual Private Network) encrypts your Internet connection and routes your traffic through a VPN provider’s servers, masking your IP address from local network observers, ISPs, and websites. Using a VPN can prevent your ISP or local Wi-Fi owner from tracking what sites you visit (they only see a connection to the VPN), and can help circumvent some regional restrictions or filtering.
However, VPNs simply shift your trust: Instead of your ISP seeing your activity, your VPN provider can, so you must trust their privacy policies and infrastructure. Quality and privacy protections vary widely from one VPN company to another.
I see over and over again that Mullvad VPN is the best, I am in no way affiliated with them this is just what I hear. They allow you to pay with cash completely anonymously and keep very minimal metadata. Metadata is a big deal, the US gov has admitted to killing people based solely on their metadata.
Your ISP almost certainly does sketchy stuff with your data, personally I would rather trust a company like Mullvad whose whole reputation is based on their trustworthiness, transparency, and data protection.
You can use a VPN with Tor, but it's not recommended by the Tor Project unless you're an advanced user who knows how to configure both in a way that doesn't compromise your privacy.
Popular VPNs on NixOS
-
Mullvad VPN Mullvad VPN uses WireGuard under the hood and only works if
systemd-resolvdis enabled.
Setting up Tailscale
I was surprised at how easy this actually was to set up. Either go to
https://www.tailscale.com and/or download the app for either Android or IOS,
sign up with your identity provider, and click Start connecting devices ->
To add tailscale to NixOS:
# tailscale.nix
{...}: {
services.tailscale.enable = true;
# Tell the firewall to implicitly trust packets routed over Tailscale:
networking.firewall.trustedInterfaces = ["tailscale0"];
}
Tailscale will automatically use the hostname of your device as the name of the network. If you want to change it to something else:
sudo tailscale set --hostname=<name>
# You can also give your account a nickname
sudo tailscale set --nickname=<name>
This allows you to refer to your network by name rather than IP address.
Tailscale uses MagicDNS which is enabled by default, and they recommend you keep it enabled.
The docs say that by default, devices in your tailnet prefer their local DNS settings and only use the tailnet's DNS servers when needed. I had to completely disable my Androids DNS settings for tailscale to access the internet through MagicDNS.
sudo tailscale set --accept-dns=false
To connect to tailscale after rebuilding you can run:
sudo tailscale up
Use nslookup to review and debug DNS responses:
nslookup google.com
Server: 127.0.0.1
Address: 127.0.0.1#53
Non-authoritative answer:
Name: google.com
Address: 142.251.40.206
Name: google.com
Address: 2a00:1450:4001:827::200e
- The
127.0.0.1#53indicate that instead of using the DNS server pushed by your ISP, router, or Tailscale's MagicDNS, the system is sending all DNS requests through the loopback device todnscrypt-proxyin my case.
Get the status of your connections to other Tailscale devices:
tailscale status
1 2 3 4 5
100.1.2.3 device-a apenwarr@ linux active; direct <ip-port>, tx 1116 rx 1124
100.4.5.6 device-b crawshaw@ macOS active; relay <relay-server>, tx 1351 rx 4262
100.7.8.9 device-c danderson@ windows idle; tx 1214 rx 50
100.0.1.2 device-d ross@ iOS —
-
There is much more you can do with Tailscale, including integrating Mullvad-VPN and using Exit Nodes.
Encrypted DNS
DNS (Domain Name System) resolution is the process of translating a website's domain name into its corresponding IP address. By default, this traffic isn't encrypted, which means anyone on the network, from your ISP to potential hackers, can see the websites you're trying to visit. Encrypted DNS uses protocols to scramble this information, protecting your queries and responses from being intercepted and viewed by others.
❗ NOTE: There are many other ways for someone monitoring your traffic to see what domain you looked up via DNS that it's effectiveness is questionable without also using Tor or a VPN. Encrypted DNS will not help you hide any of your browsing activity.
There are 3 main types of DNS protection:
-
DNS over HTTPS (DoH): Uses the HTTPS protocol to encrypt data between the client and the resolver.
-
DNS over TLS (DoT): Similar to (DoH), differs in the methods used for encryption and delivery using a separate port from HTTPS.
-
DNSCrypt: Uses end-to-end encryption with the added benefit of being able to prevent DNS spoofing attacks.
Useful resources:
✔️ Click to Expand DNS Resources
Hot Take:
The following sets up dnscrypt-proxy using DoH (DNS over HTTPS) with an oisd blocklist, they both come directly from the Wiki:
Add oisd to your flake inputs:
# flake.nix
inputs = {
oisd = {
url = "https://big.oisd.nl/domainswild";
flake = false;
};
};
❗ NOTE: The
oisdblocklist is a plain text file that updates frequently. This can causenh os switchto fail with aNarHashmismatch error. To fix this, you need to runnix flake updateto refresh the blocklist and its hash in yourflake.lockfile. After that, you can run yournhcommand again.
And the import the following into your configuration.nix:
# dnscrypt-proxy.nix
{
pkgs,
lib,
inputs,
...
}: let
blocklist_base = builtins.readFile inputs.oisd;
extraBlocklist = '''';
blocklist_txt = pkgs.writeText "blocklist.txt" ''
${extraBlocklist}
${blocklist_base}
'';
hasIPv6Internet = true;
StateDirectory = "dnscrypt-proxy";
in {
networking = {
# Set DNS nameservers to the local host addresses for iPv4 (`127.0.0.1`) & iPv6 (::1)
nameservers = ["127.0.0.1" "::1"];
# If using dhcpcd
# dhcpcd.extraConfig = "nohook resolv.conf";
# If using NetworkManager
networkmanager.dns = "none";
};
services.resolved.enable = lib.mkForce false;
# See https://wiki.nixos.org/wiki/Encrypted_DNS
services.dnscrypt-proxy2 = {
enable = true;
# See https://github.com/DNSCrypt/dnscrypt-proxy/blob/master/dnscrypt-proxy/example-dnscrypt-proxy.toml
settings = {
# See https://github.com/DNSCrypt/dnscrypt-resolvers/blob/master/v3/public-resolvers.md
sources.public-resolvers = {
urls = [
"https://raw.githubusercontent.com/DNSCrypt/dnscrypt-resolvers/master/v3/public-resolvers.md"
"https://download.dnscrypt.info/resolvers-list/v3/public-resolvers.md"
];
minisign_key = "RWQf6LRCGA9i53mlYecO4IzT51TGPpvWucNSCh1CBM0QTaLn73Y7GFO3";
cache_file = "/var/lib/${StateDirectory}/public-resolvers.md";
};
# sources.quad9-resolvers = {
# urls = [
# "https://quad9.net/dnscrypt/quad9-resolvers.md"
# "https://raw.githubusercontent.com/Quad9DNS/dnscrypt-settings/main/dnscrypt/quad9-resolvers.md"
# ];
# minisign_key = "RWTp2E4t64BrL651lEiDLNon+DqzPG4jhZ97pfdNkcq1VDdocLKvl5FW";
# cache_file = "/var/cache/dnscrypt-proxy/quad9-resolvers.md";
# };
# Use servers reachable over IPv6 -- Do not enable if you don't have IPv6 connectivity
ipv6_servers = hasIPv6Internet;
block_ipv6 = ! hasIPv6Internet;
blocked_names.blocked_names_file = blocklist_txt;
require_dnssec = true;
# Logs can get large very quickly...
require_nolog = false;
# This stops dns malware filtering, etc. if true
require_nofilter = false;
dnscrypt_servers = true;
# If you want, choose a specific set of servers that come from your sources.
# Here it's from https://github.com/DNSCrypt/dnscrypt-resolvers/blob/master/v3/public-resolvers.md
# If you don't specify any, dnscrypt-proxy will automatically rank servers
# that match your criteria and choose the best one.
# server_names = [ ... ];
# server_names = ['quad9-dnscrypt-ip6-filter-pri', 'quad9-dnscrypt-ip4-filter-pri', 'mullvad-adblock-d'];
};
};
systemd.services.dnscrypt-proxy2.serviceConfig.StateDirectory = StateDirectory;
}
❗️ NOTE: Upon testing dnscrypt-proxy on Arch, it was able to route the browser through the proxy, removing the need for Max Protection. I'm still currently on Arch and plan to test this further ASAP. We test the above settings further down, but I'm curious why the browser isn't routed correctly...
- Above, we have a local DNS proxy that encrypts and forwards queries.
# You should see that dnscrypt-proxy chooses the Server with the lowest initial latency
sudo systemctl status dnscrypt-proxy2
# verify that dnscrypt-proxy is listening
sudo ss -lnp | grep 53
# Test a DNS query, if you get valid responses it's working
dig @127.0.0.1 example.com +short
# check the logs
sudo journalctl -u dnscrypt-proxy2
dnscrypt-proxy2 acts as your local DNS resolver listening on your machine
(127.0.0.1) for IPv4 and ::1 for iPv6.
The system's DNS settings (networking.nameservers) point to localhost, so
all DNS queries go to dnscrypt-proxy accept for your browser. Your browser
has to be configured separately with a local resolver in which I haven't figured
out yet. I recommend setting your browsers DNS over HTTPS to strict with a
respected custom DNS resolver such as https://dns.quad9.net/dns-query.
inputs.oisd refers to the flake input oisd blocklist, it prevents your device
from connecting to unwanted or harmful domains.
dnscrypt-proxy2 then encrypts and forwards our DNS requests to third-party
public DNSCrypt or DoH servers.
MAC Randomization
Android and iPhone already implement MAC Randomization by default.
MAC Randomization enhances privacy by making it harder for third parties to track users across different networks.
Randomizing MAC adresses obscures a device's unique hardware identity when scanning for or connecting to Wi-Fi, blocking passive tracking as well as location tracking across networks.
If you use NetworkManager you can set MAC randomization with:
networking = {
networkmanager = {
enable = true;
wifi.scanRandMacAddress = true;
wifi.macAddress = "random";
plugins = [];
};
Right when I rebuilt, I got an alert from my router saying that a new device just connected to the network.
There is also a utility for viewing/manipulating the MAC address of network
interfaces, pkgs.macchanger. This is less reliable than the NetworkManager
setting.
Firewalls
NixOS includes an integrated firewall based on iptables/nftables.
✔️ Click to Expand Firewall Resources
The following firewall setup is based on the dnscrypt setup above utilizing nftables.
This nftables firewall configuration is a strong recommended practice for
enforcing encrypted DNS on your system by restricting all outbound DNS traffic
to a local dnscrypt-proxy process. It greatly reduces DNS leak risks and
enforces privacy by limiting DNS queries to trusted, encrypted upstream
servers.(This was edited on 08-08-25) replace <DNSCRYPT-UID> with the UID
given from the command ps -o uid,user,pid,cmd -C dnscrypt-proxy:
{ ... }: {
networking.nftables = {
enable = true;
ruleset = ''
table inet filter {
chain output {
type filter hook output priority 0; policy accept;
# Allow localhost DNS for dnscrypt-proxy2
ip daddr 127.0.0.1 udp dport 53 accept
ip6 daddr ::1 udp dport 53 accept
ip daddr 127.0.0.1 tcp dport 53 accept
ip6 daddr ::1 tcp dport 53 accept
# Allow dnscrypt-proxy2 to talk to upstream servers
# Replace <DNSCRYPT-UID> with:
# ps -o uid,user,pid,cmd -C dnscrypt-proxy
meta skuid <DNSCRYPT-UID> udp dport { 443, 853 } accept
meta skuid <DNSCRYPT-UID> tcp dport { 443, 853 } accept
# Block all other outbound DNS
udp dport { 53, 853 } drop
tcp dport { 53, 853 } drop
}
}
'';
};
networking.firewall = {
enable = true;
allowedTCPPorts = [
# Ports open for inbound connections.
# Limit these to reduce the attack surface.
22 # SSH – Keep open only if you need remote access.
# To change the SSH port in NixOS:
# services.openssh.ports = [ 2222 ];
# Update this list to match the new port.
# 53 # DNS – Only if running a public DNS server.
# 80 # HTTP – Only if hosting a website.
# 443 # HTTPS – Only if hosting a secure website.
];
allowedUDPPorts = [
# Ports open for inbound UDP traffic.
# Most NixOS workstations won't need any here.
# 53 # DNS – Only if running a public DNS server.
];
};
}
✔️ Click to Expand Tip on changing the default SSH Port
❗ TIP: Reduce SSH noise by changing the default port On most systems, SSH listens on TCP port 22 — which means automated bots and scanners will hit it constantly. While this doesn’t replace real security measures, moving SSH to a different port drastically cuts down on drive-by brute-force attempts you’ll see in your logs.
In NixOS, change both the SSH daemon port and your firewall rule:
# Example: Move SSH to port 2222 networking.firewall.allowedTCPPorts = [ 2222 ]; services.openssh.ports = [ 2222 ];
- After rebuilding, test from another terminal/session before closing your existing one:
ssh -p 2222 user@host
nft is a cli tool used to set up, maintain and inspect packet filtering and
classification rules in the Linux kernel, in the nftables framework. The Linux
kernel subsystem is known as nftables, and 'nf' stands for Netfilter.--man nft
sudo nft list ruleset
- Since we declare our firewall, we'll only use
nftto inspect our ruleset.
NixOS Firewall vs nftables Ruleset
networking.nftables: This section provides a raw nftables ruleset that gives
you granular, low-level control. The rules here are more specific and are meant
to handle the intricate logic of the DNS proxy setup. They will be applied
directly to the kernel's nftables subsystem and prevent DNS leaks.
networking.firewall: This is a higher-level, simpler NixOS option that uses
iptables rules to open ports for inbound traffic. The rules defined here
(allowing port 22) is for incoming SSH connections to the machine, not for
outbound traffic, so they do not interfere with the nftables rules that filter
the outgoing traffic. (Make sure to comment out or remove this if you don't SSH
into your machine).
The firewall ensures only authorized, local encrypted DNS proxy process can
speak DNS with the outside world, and that all other DNS requests from any other
process are blocked unless they're to 127.0.0.1 (our local proxy). This is a
robust policy against both DNS leaks and local compromise.
Testing
Review listening ports: After each rebuild, use ss -tlpn, nmap or netstat
to see which services are accepting connections. Close or firewall anything
unnecessary.
You can also test firewall DNS restrictions using dig:
dig @127.0.0.1 example.com # Should work
dig @8.8.8.8 example.com # Should fail/time out for normal users
- This test is actually what alerted me of an improper configuration in the
above firewalls nftables rules allowing me to fix it. Initially the second
digcommand gave results letting me know that the restrictions weren't being applied correctly.
Since we defined an output chain inside table inet filter with the line:
type filter hook output priority 0; policy accept;
This attaches the chain to the kernel’s OUTPUT hook, so all locally generated packets, including DNS queries are filtered by this chain.
Within this chain, the rules:
-
Explicitly allow DNS queries to localhost addresses (
127.0.0.1and::1). -
Allow the
dnscrypt-proxyprocess (running with UID62396) to send DNS queries on ports 443 and 853 (for DNS-over-HTTPS and DNS-over-TLS). -
Drop all other outbound DNS traffic on ports
53and853.
Because of this setup, dig queries to your local resolver at 127.0.0.1 pass,
but queries directly to public DNS servers like 8.8.8.8 are blocked for
users/processes other than the allowed DNS proxy.
OpenSnitch
Opensnitch is an open-source application firewall that focuses on monitoring and controlling outgoing network connections on a per-application basis.
This can be used to block apps from accessing the internet that shouldn't need to (i.e., block telemetry and more). Opensnitch will report that the app has attempted to make an outbound internet connection and block it or allow it based on the rules you set.
Resources
✔️ Click to Expand Resources
-
Surveillance Self-Defence has a lot of helpful info to protect your privacy.
-
What is Fingerprinting, more than you realize is being tracked constantly.
-
oisd.nl the oisd website
-
For potentially dangerous file types like PDFs, office documents, or images, especially those downloaded from untrusted sources such as torrents, consider converting them to a safe PDF format with dangerzone. Dangerzone not only removes metadata but also applies robust sanitization to neutralize malicious content.
-
NixOS Wiki LibreWolf, the options in the wiki make it less secure and aren't recommended settings to use. They explicitly disable several of LibreWolf's default privacy-enhancing features, such as fingerprinting resistance and clearing session data on shutdown.
-
LibreWolf Features You still need to enable DNS over HTTPS through privacy settings.
If you should trust the U.S. Governments recommendations is another story but it can be good to compare and contrast with other trusted resources. You'll have to think whether the CISA recommending that everyone uses Signal is solid advice or guiding you towards a honeypot, I can't say for sure.
-
Mozilla Firefox Security Technical Implementation Guide The STIG for Mozilla Firefox (Security Technical Implementation Guide) is a set of security configuration standards developed by the U.S. Department of Defense. They are created by the Defense Information Systems Agency (DISA) to secure and harden DoD information systems and software.
-
Firefox Relay can be used to create email aliases that forward to your real email address. The paid plan also lets you create phone number aliases that forward to your phone number.