You should be using systemd presets

I've been using systemd for a few years. Every now and then, I'll learn about some powerful under-utilized feature (slices and timers are my favorite under-utilized features). Recently, I learned about preset files, because I'm building my own packages for our Rocky Linux base images, and that had me reading the Red Hat packaging manual. Presets allow you to specify what units to enable/disable by default, and if you're setting up a system or creating a package, you should be using presets instead of systemctl enable or systemctl disable.

This is especially important if you are creating a package - any services which you have enabled/disabled with the CLI will be reset to the presets whenever a system goes through its first boot process (which would happen if you built an image and set it up properly), and if your package is incompatible with a certain service that is normally enabled, your package will break until the administrator takes action. This makes administrators think the issue is systemd, when it is really just bad packaging behavior. Presets also allow you to define, by policy, what you want running or not, and be sure that you can return to this state by running systemctl preset-all.

Packages should be putting presets at /usr/lib/systemd/system-preset/XX-package.preset and administrators should be putting presets at /etc/systemd/system-preset/XX-foo.preset (this directory may not exist by default). Note that the systemd manpage discourages packages from using presets this way, but they are specifically referring to OS vendor packages - e.g., Rocky Linux should not ship hundreds of preset files and should instead ship one or two big files in a central package. Third-party packages (like amazon-ec2-net-utils linked above) should be installing preset files, and if they need to actually disable/enable services in their post-installation script, they should be using systemctl preset unitname instead of systemctl enable unitname or systemctl disable unitname.

A preset file looks like this:

1
2
3
4
5
6
7
8
9
enable systemd-networkd.service
enable systemd-resolved.service
disable NetworkManager.service
disable NetworkManager-dispatcher.service
disable NetworkManager-wait-online.service

# Disable mdmonitor since we don't use mdadm
disable mdmonitor.service
disable mdmonitor-oneshot.service

Preset filenames start with a priority number from 00 to 99. systemd sorts all presets by filename, and does whatever the first match says and ignores any subsequent entries for that unit. Additionally, priority 99 disables all units not otherwise enabled with a disable * (at least on Enterprise Linux). Because of this, if you want your presets to be additive (i.e., you don't need to override any OS vendor defaults), you should use priority 98. This should also be the default priority number for packages, unless they need to disable normally enabled services. If you want to override OS vendor defaults, you need to put them lower than priority 90 (again, at least on Enterprise Linux). I choose to use priority 50 for this, because it's easier to type than 89 ☺.

I haven't found a need to use the secondary way to override presets, which is that /etc takes precedence over /usr/lib if two files are named the same, and I would suggest not depending on this if you can avoid it because it might be just a bit too much magic.

If you want to see what the ultimate state of your presets ends up being, you can run systemctl list-unit-files.