Why can't I get DNS nameservers to stick?

TLDR - how can I get my nixos machine to use 127.0.0.1 as its primary DNS nameserver and then use 1.1.1.1 as a fallback nameserver if 127.0.0.1 fails. I don’t want to install systemd-resolved and I’ve tried all manner of configuration settings with networking.nameservers and resolveconf to no success.

I’m running nixos 24.11. I’m using systemd-networkd to manage internet connection. I’m running a pihole docker container on this machine that sucessfully resolves DNS queries directed at it.

The long story short is that I’m trying to figure out a way to have a “fallback” DNS for this machine if/when the pihole docker container doesn’t work. For example, if pihole is stopped and the local image cache is accidentally deleted, I need this machine to have a fallback DNS so it can download the pihole docker image successfully.

If I install systemd-resolved, it collides with pihole on port 53, so I uninstalled systemd-resolved and don’t want to use that.

That leaves potentially from what I can see setting the nameservers via networking.nameservers or networking.resolvconf but I can’t get anything to work.

Here are some things that don’t work:

This variation doesn't actually populate anything into /etc/resolv.conf and the machine defaults to ::1 as its primary nameserver with no fallbacks:

  services.resolved = {
    enable = lib.mkForce false; # ensure not enabled because running pihole on port 53
  };

  networking = {
    nameservers = [
      "127.0.0.1"
      "1.1.1.1"
      "9.9.9.9"
    ];
    resolvconf = {
      enable = lib.mkForce false;
    };
  };

Here is another variation that doesn't work:

  services.resolved = {
    enable = lib.mkForce false; # ensure not enabled because running pihole on port 53
  };

  networking = {
    resolvconf = {
      enable = true;
      useLocalResolver = true; # this correctly adds "name_servers=127.0.0.1 ::1" to /etc/resolvconf.conf, which in turn populates /etc/resolv.conf with "nameserver 127.0.0.1" as primary and "nameserver ::1" as secondary
      extraConfig = "name_servers='1.1.1.1'"; # this appends "nameserver 1.1.1.1" to /etc/resolvconf.conf, which in turn populates /etc/resolv.conf but then it defaults to using 1.1.1.1 as primary which is not what I want
      extraConfig = "name_servers='127.0.0.1 1.1.1.1'"; # this only populates 127.0.0.1 into /etc/resolv.conf and 1.1.1.1 does not appear/is not used as a fallback
    };
  };

If you know what you want resolv.conf to be, and you aren’t running any other services like NetworkManager that would modify it (or you’ve configured them not to), why not simply do this?

environment.etc."resolv.conf".text = ''
  nameserver 127.0.0.1
  nameserver 1.1.1.1
'';

Bonus, you won’t have to force-disable resolvconf with this, because it’s disabled by default if a resolv.conf file is defined in this way.

This got it, thanks!