Why this matters
You need cron to run with one extra setting. The obvious move is to open its unit file and type it in. It works - until the next sudo apt upgrade installs a new version of the package, replaces the file, and your change silently vanishes. Nobody notices until 3am. This lesson is about where changes go instead.
What you need to know already: 2.1 (units, sections, systemctl cat), paths and directories (1.3), sudo (1.11).
Three directories, one winner
systemd looks for foo.service in these directories, in this order, and the first file it finds wins completely:
/etc/systemd/system/- yours, the administrator's. Survives upgrades./run/systemd/system/- generated at runtime;/runis emptied at every reboot./usr/lib/systemd/system/- the package's (what apt installed)./libis a symlink (a shortcut that points to another path) to/usr/libon modern Ubuntu, so both paths name the same file.
systemd-analyze unit-paths prints the full search list, in order.
Never edit the file under /usr/lib. Not because it will not work - it works perfectly, until apt upgrade replaces the file and your change silently disappears, usually on the machine nobody remembers you touched.
Drop-ins are the right answer
A drop-in is a small extra file that changes only the directives you list, on top of the packaged unit, instead of replacing the whole file. It is also called an override. It lives in a directory named after the unit plus .d:
/etc/systemd/system/cron.service.d/override.conf
Any .conf file in that directory is merged on top of the packaged unit, in alphabetical order. You write only what you change - with its section header, so systemd knows where the directive belongs:
[Service]
Environment=LAB=1
(Environment= sets an environment variable for the program: a named value, here LAB = 1, that the program can read when it starts. 2.21 is all about them.)
sudo systemctl edit cron creates that file for you, in the right place, opens it in a text editor, and tells systemd to re-read it when you save. Use it rather than typing the path by hand.
The editor it opens is nano, a simple terminal text editor. The keys you need: type normally to edit; Ctrl+O then Enter saves ("write Out"); Ctrl+X exits. The shortcut list at the bottom of the screen uses ^ to mean Ctrl.
Things worth knowing:
systemctl edit --full croncopies the entire unit to/etcinstead. Use it when you need to change something a drop-in cannot express.- Some directives are lists, and lists add up. A second
ExecStart=in a drop-in is added to the first rather than replacing it. To replace one, first clear it with an empty assignment -ExecStart=on its own line - then give the new value. Same forEnvironment=andExecStartPre=. - Dependencies are the exception.
After=,Wants=,Requires=(2.14) cannot be emptied in a drop-in - a drop-in can only add to them. To remove one you override the whole unit (systemctl edit --full).
Undo
sudo systemctl revert cron
Deletes every drop-in and any copy under /etc, putting the unit back to exactly what the package ships. It prints each file it deleted.
systemctl cat and systemctl status both show drop-ins, so you can always see what has been layered on: cat prints each drop-in after the main file with its path, and status grows a Drop-In: line.
What you can now do
- change a packaged service without touching the package's file
- see which files make up a unit, and undo your change in one command