Jump to content

Portmaster

From Official NixOS Wiki
Revision as of 13:03, 18 August 2026 by WitteShadovv (talk | contribs) (Add first draft of Portmaster package and module entry)
(diff) ← Older revision | Latest revision (diff) | Newer revision → (diff)

Portmaster is a free and open source application firewall developed by Safing.[1] It monitors and controls network connections per application, so rules follow the program rather than the port. A package and a service module are available on the unstable channel and will ship with NixOS 26.11.

Installation

System setup

Add the following to your system configuration:

services.portmaster.enable = true;

This starts the portmaster.service daemon, installs the desktop client into the system environment, and loads the nfnetlink_queue kernel module. The desktop client starts in the background with graphical sessions and authenticates against the package's read-only binary directory, so it works without any further setup. When the service stops, leftover iptables rules are cleaned up automatically.

For all module options, refer to services.portmaster.

Configuration

Basic

Global settings can be managed declaratively through services.portmaster.settings:

services.portmaster = {
  enable = true;
  settings = {
    "core/log/level" = "warning";
    "dns/nameservers" = [
      "dot://dns.quad9.net?ip=9.9.9.9&name=Quad9&blockedif=empty"
    ];
  };
};

Settings are merged from three sources, where later sources override earlier ones: settings, then settingsFile, then secretsFile. Use secretsFile for values that must not be copied to the world-readable Nix store.

Note: When any of these options or declarative profiles are used, the module owns Portmaster's runtime config.json. Global settings changed only through the UI are replaced at the next service start, so keep all global settings in your NixOS configuration.

Portmaster stores its mutable state, configuration, and logs under services.portmaster.stateDir, which defaults to /var/lib/portmaster. Changing it does not migrate existing state.

Set services.portmaster.settings.devmode to true only when you need unrestricted browser or debugging access to the local API at http://127.0.0.1:817. The packaged desktop client does not need it.

Advanced

Application profiles can be declared in your NixOS configuration. The module derives fingerprints from packages using regular expressions that ignore the Nix store hash and the package version, and that also match Nix generated .program-wrapped executables. Profiles therefore keep working across rebuilds and package updates. They are imported through Portmaster's local API, and rebuilds update existing profiles in place instead of creating duplicates.

services.portmaster = {
  enable = true;
  profilePrefix = "[NixOS] ";

  profiles = {
    Firefox = {
      packages = [ pkgs.firefox ];
      settings.filter.defaultAction = "permit";
    };

    Vesktop = {
      fingerprints = [
        {
          type = "env";
          key = "CHROME_DESKTOP";
          operation = "equals";
          value = "vesktop.desktop";
        }
      ];
    };
  };
};

Some packages start their real executable outside bin. Describe those layouts explicitly:

services.portmaster.profiles.Brave.packages = [
  {
    package = pkgs.brave;
    directory = "opt/brave.com/brave";
  }
];

A package entry accepts package, type, storeNameRegex, directory, name, wrapped, strictHead, and strictLast fields. Manual fingerprints support the types path, cmdline, env, and tag with the operations equals, prefix, and regex. The packages and fingerprints lists are merged, and at least one of them must be non-empty.

⚠︎
Warning: Package name matching is a convenience, not a security boundary against local Nix users. Anyone who can add arbitrary store paths can create a derivation with a matching name. Use manually chosen fingerprints when that threat is relevant to your setup.

Fingerprints are alternatives: a process matches when any fingerprint matches, so broad regular expressions can match unintended applications. Removing a profile declaration does not remove a profile that Portmaster has already imported. Changing fingerprints changes the derived profile identity, which can leave the previous imported profile behind.

Tips and tricks

  • Use profilePrefix to make module managed profiles easy to recognize in the Portmaster UI.
  • The binary self-updater is disabled in the NixOS package because Nix owns the installed files. Intelligence and filter list data updates keep working and are stored under stateDir.

Troubleshooting

Port 53 conflicts

Portmaster runs its own local nameserver on port 53 of localhost.[2] The module does not disable systemd-resolved or other DNS services for you. If another service already listens on port 53, resolve the conflict yourself, for example by disabling systemd-resolved or its stub listener.

DNS queries that arrive through systemd-resolved cannot be attributed to the originating process, which weakens per-application filtering.[2] Setups using systemd-networkd have also seen VPN provided split DNS zones fail to resolve.[3]

firewalld

The Portmaster service declares a systemd conflict with firewalld.service. The two cannot run at the same time.

First start

Portmaster downloads its intelligence and filter list data on first start, so the first run needs a working network connection. If the download fails, filtering can be impaired until the data is fetched. Restarting the service retries the download.

Declarative profiles fail to import

The import runs in a separate unit, portmaster-managed-profiles.service, which waits up to 60 seconds for the Portmaster API to become ready. Check its status and the reason for a rejected profile with:

# journalctl -u portmaster-managed-profiles

Logs

The daemon logs to the journal and to logs under stateDir:

# journalctl -u portmaster

See also

References