Service managers and unit files

A supervised process runs in the environment its unit declares, not the one in your shell.

A service manager such as systemd starts, supervises, and restarts long-running processes. It builds each process's world from the unit file: the command line, working directory, user, environment, resource limits, and restart policy. Nothing else carries over. Your interactive shell's current directory, PATH, aliases, and exported variables are all absent.

That is why "it works when I run it" is weak evidence. A hand-started process inherits your shell's context. The managed one gets / as its working directory and a minimal PATH. The fix belongs in the unit (WorkingDirectory=, Environment=, EnvironmentFile=) or in the program (absolute paths), never in someone's login profile.

Things to internalise:

  • The unit you edited is not the unit that is running. Managers cache definitions. After editing, run daemon-reload, then restart or reload. Status output warns when the file on disk has changed.
  • Restart policy hides crash loops. Restart=on-failure restarts the process until the start limit trips. The journal then shows a burst of identical failures followed by "start request repeated too quickly". Read the first failure.
  • Enable and start are different. Enabling links the unit into a boot target. Starting runs it now. A fix that is not enabled disappears at the next reboot.
  • Reload is a contract. reload runs ExecReload=, often kill -HUP $MAINPID. It only works if the program handles that signal, typically by re-reading config and reopening log files.
  • Timers are schedulers. A timer starts a service on a schedule. Killing the service's process does not stop the timer from starting it again.

The Twelve-Factor "disposability" factor is the application side of the same bargain. A process should start fast and shut down gracefully on SIGTERM, because the manager will do both often.