Removing system packages

Hello Nixers :wave:t2:

I am very new to Nix and need some help figuring out how to remove certain system packages to trim the NixOS down. For context, I am using NixOS inside of LXC containers at the moment and I am trying to shrink the image size. So far I got down to 1.6 Gb, but I feel like I can trim some things even further (coming from Gentoo world where my minimal usable builds were under 200 Mb).

At the moment I am using nix-env --list-generations --profile /nix/var/nix/profiles/system to get me a full list of dependencies required by the system profile. On that list I have quite a few things that I would like to get rid of, for example:

/nix/store/pxp56zkk6wbzf8nrnsq89q73vswy34w8-libressl-3.6.1
/nix/store/0hmm7s3xsip57iza41ybzbqg2aln548s-libressl-3.6.1-nc
/nix/store/di2xpgzgmglq6p6zq4qc8wzlvr7nvzad-mdadm-4.2
/nix/store/9xdak9iv5vvq7xqb2sfy21f3fkxk1c4p-system-sendmail-1.0
/nix/store/0hzd3p6ycddp4mk3scwkqclljfgk4vda-btrfs-progs-6.1.2
/nix/store/sxwpyh0zhg3dwf7izcgjnnya1lskvc2s-mailcap-2.1.53

And many others. Looking for their referrers, I often end up in system-path, system-units or system-shutdown paths and I am struggling to figure out how I can trim them down. For example:

# nix-store --query --referrers /nix/store/di2xpgzgmglq6p6zq4qc8wzlvr7nvzad-mdadm-4.2
/nix/store/di2xpgzgmglq6p6zq4qc8wzlvr7nvzad-mdadm-4.2
/nix/store/0fi5f12xzagldmfni8kb27kzaa9a44h1-system-units
/nix/store/37gpvcj3r1g9qjpr15vv30q6122zc7hn-system-path
/nix/store/5vx86l25fm4wnf95qfiilvxrsriljnk5-system-path
/nix/store/97h0pmajnnyy7zxs4mdxgkjamim589pr-system-units
/nix/store/hhivdc08yk8lmiwaxs1gjxr1hyxx9fmr-system-shutdown
/nix/store/z9zi0vbw3wginj314fkd2wcvgf5l0pvl-system-shutdown

# nix-store --query --referrers /nix/store/0hmm7s3xsip57iza41ybzbqg2aln548s-libressl-3.6.1-nc
/nix/store/37gpvcj3r1g9qjpr15vv30q6122zc7hn-system-path
/nix/store/5vx86l25fm4wnf95qfiilvxrsriljnk5-system-path

What is the best way to approach this?

Appreciate any ideas!

It would help if you shared your config, but some things I know you can get rid of:

environment.defaultPacakages = [];

https://search.nixos.org/options?channel=22.11&show=environment.defaultPackages&from=0&size=50&sort=relevance&type=packages&query=Systempackages

But be careful because this removes nano and you might be left with no way to edit your config.

There’s also lots of required packages here https://github.com/NixOS/nixpkgs/blob/cc4bb87f5457ba06af9ae57ee4328a49ce674b1b/nixos/modules/config/system-path.nix#L10 but trying to remove them can be hazardous because the standard NixOS tools like nixos-rebuild probably depend on them.

As for those system services, you might be able to remove them if you figure out what systems.services configuration sets them up. You’re probably going to have to grep the NixOS source code for things like “system-shutdown”.

Hey @ryantm,

Really appreciate your response.

This is my current config:

{ lib, modulesPath, pkgs, ... }: {
  system.stateVersion = "22.11";

  imports = [
    "${toString modulesPath}/virtualisation/lxc-container.nix"
    ./coreutils.nix
    ./dbus.nix
    ./openssh.nix
    ./systemd.nix
    ./util-linux.nix
    ./vim.nix
  ];

  environment.defaultPackages = [];
  environment.systemPackages = with pkgs; [ git ];

  i18n.defaultLocale = "en_AU.UTF-8";

  networking.dhcpcd.enable = false;
  networking.firewall.enable = false;
  networking.hostName = "nixos-lxc";
  networking.resolvconf.enable = false;
  networking.useDHCP = false;
  networking.useNetworkd = true;

  services.nscd.enable = false;
  services.logrotate.enable = lib.mkForce false;

  system.nssModules = lib.mkForce [];

  security.pam.services.su.forwardXAuth = lib.mkForce false;

  # Remove once https://github.com/NixOS/nixpkgs/issues/195795 is fixed
  programs.nano.syntaxHighlight = false;

  fonts.fontconfig.enable = false;

  time.timeZone = "Australia/Sydney";
}

I have a few imports there as well, as you might notice, they are just configuring things in a particular way I need, for example, in dbus.nix I disable X11 integration:

{ ... }: {
  nixpkgs.overlays = [ ( final: prev: {
    dbus = prev.dbus.override {
      x11Support = false;
    };
  } ) ];
}

and in util-linux.nix I disable translations:

{ ... }: {
  nixpkgs.overlays = [ ( final: prev: {
    util-linux = prev.util-linux.override {
      nlsSupport = false;
      translateManpages = false;
    };
  } ) ];
}

and so forth.

I have actually intentionally got rid of nano and replaced it with Vim, so no problem here at all. Thanks for the warning though.

I do understand dangers associated with removing some or all of the packages in that list - I have a lot of experience with Linux, just very little with Nix, i.e. I know what I want to do, just don’t know how to :sweat_smile: (yet)… Do you happen to know how I can actually modify or replace this requiredPackages list? I am quite sure I can get away without cpio, netcat or su in my LXC container.

Also, with that same requiredPackages list I have noticed that mdadm isn’t there, but it is still referenced if I do:

# nix-store --query --referrers /nix/store/di2xpgzgmglq6p6zq4qc8wzlvr7nvzad-mdadm-4.2
...
/nix/store/37gpvcj3r1g9qjpr15vv30q6122zc7hn-system-path
/nix/store/5vx86l25fm4wnf95qfiilvxrsriljnk5-system-path
...

any idea how it is getting there?

Thanks in advance! :bowing_man:t2:

Danger danger don’t copy this without possibly bricking everything:

environment.systemPackages = lib.mkForce [];

This will make it so there are NO system packages installed at all. It will probably break terribly.

1 Like

I suspect mdadm is coming in because of some file system support that maybe you don’t need. I don’t know how to stop that off the top of my head though.

Thank you very much for your help! I will be playing with the mkForce on systemPackages and see how far I can get.

Let’s see if anyone else might have any ideas about mdadm too. :crossed_fingers:t2:

:wave:t2:so, after digging for quite a while and wrapping my head around the whole concept of nixpkgs modules, I have finally found my answer. The swraid module unconditionally adds the mdadm package to the environment.systemPackages.

I have reported the issue on GitHub, but for the time being I solved it by creating the module replacement:

{ config, lib, ... }:


with lib;


let


  cfg = config.boot.initrd.services.swraid;


in




{
  disabledModules = [ "tasks/swraid.nix" ];


  options.boot.initrd.services.swraid = {
    enable = (mkEnableOption (mdDoc "swraid support using mdadm")) // {
      visible = false; # only has effect when the new stage 1 is in place
    };


    mdadmConf = mkOption {
      description = mdDoc "Contents of {file}`/etc/mdadm.conf` in initrd.";
      type = types.lines;
      default = "";
    };
  };


  config = {
    assertions = [
      {
        assertion = cfg.enable != true;
        message = "swraid is forcefully disabled";
      }
    ];
  };
}

Thanks once again @ryantm for giving me some clues to figure out the right direction!

1 Like

Hey @SirGarry, would you mind sharing your latest configs, assuming you’ve kept this going? I’m highly interested in a trimmed-down version of Nix which retains support for systemd (unlike not-os).

Hey @batonac, I have abandoned this specific approach in favor of using flakes and selectively enabling modules that I need.

This article was a good source of inspiration. I plan to push my work publicly at some point, but at the moment I am not ready, because I need to figure out how to deal with secret management and other sensitive configuration (at the moment it is a clamped together mess of spaghetti).

The most complicated part for me was that modules that depend on options exposed by other modules and in the situations where I don’t want to import the said dependencies I have to create a fake module in my flake and expose those options to be set to whatever desired values I have. It is a bit of a headache and is sometimes unreliable, because module options are added, removed or changed and it requires a bit of massaging before things work fine once more.