Firefox customizations

#| file: modules/nixos/desktop/firefox.nix
{
  lib,
  config,
  pkgs,
  ...
}:
let
  cfg = config.mjm.desktop;
in
{
  config = lib.mkIf cfg.enable {
    <<config>>
  };
}

I'm using Firefox as my web browser, as I have been for a while. It's kind of the only viable browser that isn't a Chromium fork. I use mainline Firefox, not one of the many forks, because I don't really trust the forks to stay on top of updates.

The majority of my Firefox configuration is done via policies, as it's the supported way to do declarative configuration, and it provides an easy way to disable things I don't want.

Config

programs.firefox.enable = true;
programs.firefox.nativeMessagingHosts.packages = [
  <<native-messaging-hosts>>
];

Firefox of course needs to be enabled. And some extensions need native components, which will be added here alongside the configuration to install them.

programs.firefox.policies.AIControls.Default = {
  Value = "blocked";
  Locked = true;
};

I don't want any AI features in my browser, so I turn those off. There's also a GenerativeAI policy, but AIControls supersedes it.

programs.firefox.policies.DisableFirefoxStudies = true;
programs.firefox.policies.DisableFormHistory = true;
programs.firefox.policies.FirefoxSuggest = {
  WebSuggestions = true;
  SponsoredSuggestions = true;
  ImproveSuggest = true;
  Locked = true;
};
programs.firefox.policies.SearchSuggestEnabled = false;
programs.firefox.policies.UserMessaging = {
  ExtensionRecommendations = false;
  FeatureRecommendations = false;
  UrlbarInterventions = false;
  SkipOnboarding = true;
  MoreFromMozilla = false;
  FirefoxLabs = false;
  Locked = true;
};

These are privacy-focused policy settings. I'm disabling a lot of suggestions, recommendations, stuff like that.

programs.firefox.policies.DefaultBrowserSettingEnabled = false;
xdg.mime.defaultApplications = {
  "x-scheme-handler/http" = "firefox.desktop";
  "x-scheme-handler/https" = "firefox.desktop";
};

I don't need Firefox to manage my default browser. Instead, I set the scheme handler at the system level.

programs.firefox.policies.Homepage = {
  URL = "https://launch.midna.dev/";
  Locked = true;
  StartPage = "previous-session";
};
programs.firefox.policies.NewTabPage = false;

I set the home page to my personal launchpad app, but it doesn't really get used generally, because I'm always loading my previous session when firefox launches. And instead of Firefox Home, new tabs just load an empty page, to keep things fast and less distracting.

programs.firefox.policies.OverrideFirstRunPage = "";
programs.firefox.policies.OverridePostUpdatePage = "";

I don't want the extra pages loaded when Firefox is first run or after it updates. They're mostly onboarding type things that I don't really need.

programs.firefox.policies.Sync = {
  Addons = false;
  Addresses = false;
  Bookmarks = false;
  Enabled = true;
  History = false;
  OpenTabs = true;
  Passwords = false;
  PaymentMethods = false;
  Settings = false;
  Locked = true;
};

This policy isn't currently respected in normal Firefox builds, but in the event that it is later, I've added it here. I use Firefox Sync exclusively to sync my open tabs between my machines and my phone.

Preferences

Policies can be used to set individual preference values for things that don't have a policy.

programs.firefox.preferences."browser.aboutConfig.showWarning" = false;

I don't need the warning before I go poking around in about:config.

programs.firefox.preferences."privacy.globalprivacycontrol.enabled" = true;
programs.firefox.preferences."browser.contentblocking.category" = "strict";

Global Privacy Control is the successor to the Do-Not-Track header, so I want that. I also want to use strict Enhanced Tracking Protection.

Extensions

Policies can also be used to automatically install extensions.

programs.firefox.policies.ExtensionSettings."uBlock0@raymondhill.net" = {
  installation_mode = "normal_installed";
  default_area = "menupanel";
  runtime_blocked_hosts = [
    "*://*.midna.dev"
  ];
};

uBlock Origin is what I use for ad blocking, as a supplement to my DNS level ad blocking from my router. I don't think I have any major configuration changes for it.

programs.firefox.policies.ExtensionSettings."FirefoxColor@mozilla.com" = {
  installation_mode = "normal_installed";
  default_area = "menupanel";
};

The Firefox Color extension can be used to theme the colors of the default theme of Firefox. catppuccin/nix uses this extension to apply its theme.

programs.firefox.policies.ExtensionSettings."firefoxpwa@filips.si" = {
  installation_mode = "normal_installed";
  default_area = "navbar";
};
environment.systemPackages = [ pkgs.firefoxpwa ];
#| id: native-messaging-hosts
pkgs.firefoxpwa

I'm trying out using PWAs with Firefox, mainly to keep my email separate from the rest of the browser. It does seem to have some usability quirks, so I'm not sure I'll stick with it, but I'm doing it for now.

programs.firefox.policies.ExtensionSettings."{446900e4-71c2-419f-a6a7-df9c091e268b}" = {
  installation_mode = "normal_installed";
  default_area = "navbar";
  private_browsing = true;
};
programs.firefox.policies.PasswordManagerEnabled = false;
programs.firefox.policies.AutofillAddressEnabled = false;
programs.firefox.policies.AutofillCreditCardEnabled = false;

I use Vaultwarden to store my passwords, so I use the Bitwarden extension for Firefox to autofill those passwords (and other things like credit cards). Because I use this, I also don't want to use the built-in Firefox features for this, so those get disabled.

programs.firefox.policies.ExtensionSettings."sponsorBlocker@ajay.app" = {
  installation_mode = "normal_installed";
  default_area = "menupanel";
};

SponsorBlock is nice for skipping ads embedded within YouTube videos.

programs.firefox.policies.ExtensionSettings."{7a7a4a92-a2a0-41d1-9fd7-1e92480d612d}" = {
  installation_mode = "normal_installed";
  default_area = "menupanel";
};

I use Stylus to apply Catppuccin color theming to various different websites.

programs.firefox.policies.ExtensionSettings."shinigamieyes@shinigamieyes" = {
  installation_mode = "normal_installed";
  default_area = "menupanel";
};
programs.firefox.policies.ExtensionSettings."{61a05c39-ad45-4086-946f-32adb0a40a9d}" = {
  installation_mode = "normal_installed";
  default_area = "navbar";
};
programs.firefox.policies.ExtensionSettings."{19561335-5a63-4b4e-8182-1eced17f9b47}" = {
  installation_mode = "normal_installed";
  default_area = "menupanel";
};

These two extensions are for Linkding, the bookmarks manager I use. The first is for saving a new bookmark. The second injects results from Linkding into search engine result pages.

programs.firefox.policies.ExtensionSettings."idcac-pub@guus.ninja" = {
  installation_mode = "normal_installed";
  default_area = "menupanel";
};

"I still don't care about cookies" avoids all the stupid cookie banners on every website.

Search engines

programs.firefox.policies.SearchEngines =
  let
    <<mkSearchNixos>>
  in
  {
    Default = "DuckDuckGo";
    Add = [
      <<search-engines>>
    ];
    Remove = [
      "Amazon.com"
      "Bing"
      "eBay"
      "Perplexity"
    ];
  };

Search engines can also be customized via policies. I default to using DuckDuckGo instead of Google, and I remove several other search engines that are included by default but that I am unlikely to want to use. I also have several custom search shortcuts that I configure.

#| id: search-engines
(mkSearchNixos {
  name = "Nix Packages";
  type = "packages";
  alias = "np";
})
(mkSearchNixos {
  name = "NixOS Options";
  alias = "no";
})
(mkSearchNixos {
  name = "Home Manager Options";
  source = "home_manager";
  alias = "nh";
})
mkSearchNixos =
  {
    name,
    type ? "options",
    source ? null,
    alias,
  }:
  {
    Name = name;
    URLTemplate =
      "https://search.nixos.org/${type}?channel=unstable&query={searchTerms}"
      + lib.optionalString (source != null) "&source=${source}";
    IconURL = "https://search.nixos.org/images/nixos-logomark-default-gradient-none.svg";
    Alias = "@${alias}";
  };

I have shortcuts for searching Nix packages, NixOS options, and home-manager options. These all use search.nixos.org, just with different parameters, so I have a common function to generate them.

#| id: search-engines
{
  Name = "Noogle";
  URLTemplate = "https://noogle.dev/q?term={searchTerms}";
  IconURL = "https://noogle.dev/favicon.png";
  Alias = "@n";
}

Noogle is a nice little search engine for Nix library functions.

#| id: search-engines
{
  Name = "Links";
  URLTemplate = "https://links.midna.dev/bookmarks?q={searchTerms}";
  IconURL = "https://links.midna.dev/static/favicon.ico";
  Alias = "@l";
}

I have a shortcut to search my Linkding bookmarks.

#| id: search-engines
{
  Name = "Node Dashboard";
  URLTemplate = "https://graphs.midna.dev/d/rYdddlPWk/node-exporter-full?orgId=1&from=now-1h&to=now&refresh=1m&var-job=integrations/unix&var-node={searchTerms}";
  IconURL = "https://graphs.midna.dev/public/build/img/fav32.png";
  Alias = "@node";
}

The @node alias will take me to the node dashboard in Grafana for a particular machine. This shows graphs for the various metrics gathered by the node exporter, which runs on all of my local servers.

#| id: search-engines
{
  Name = "Service Logs";
  URLTemplate = "https://graphs.midna.dev/a/grafana-lokiexplore-app/explore/service/{searchTerms}/logs?from=now-1h&to=now&var-filters=service_name|=|{searchTerms}";
  IconURL = "https://graphs.midna.dev/public/build/img/fav32.png";
  Alias = "@logs";
}
{
  Name = "Host Logs";
  URLTemplate = "https://graphs.midna.dev/a/grafana-lokiexplore-app/explore/hostname/{searchTerms}/logs?from=now-1h&to=now&var-filters=hostname|=|{searchTerms}";
  IconURL = "https://graphs.midna.dev/public/build/img/fav32.png";
  Alias = "@logh";
}

These two searches will show the last hour of logs for either a particular service or a particular machine.

Proxy Information
Original URL
gemini://midna.dev/homelab/modules/nixos/desktop/firefox.gmi
Status Code
Success (20)
Meta
text/gemini;lang=en-US
Capsule Response Time
27.40766 milliseconds
Gemini-to-HTML Time
0.699457 milliseconds

This content has been proxied by September (UNKNO).