systemd Service Unit File Generator

systemd Service Unit File Generator

Fill in a command and a few options and get a complete, correctly-sectioned .service unit file — ready to drop in /etc/systemd/system/.

Service

Restart & environment

Unit file

Save as /etc/systemd/system/myapp.service, then systemctl daemon-reload && systemctl enable --now myapp.

How to use this tool

  1. Enter the command systemd should run as ExecStart — use an absolute path to the binary, since systemd does not read your shell’s PATH.
  2. Set a working directory, and the user and group the process should run as. Leaving Group blank is fine; systemd uses the user’s primary group.
  3. Pick a restart policy. on-failure is the right default for almost everything; always also restarts on a clean exit, which most services should never do.
  4. Add any environment variables, one KEY=VALUE per line. Values with spaces are quoted automatically.
  5. Copy the result to /etc/systemd/system/<name>.service, then run systemctl daemon-reload and systemctl enable --now <name>.

A systemd unit file is an INI-style document split into sections, and the section a directive lives in is not cosmetic — systemd parses [Unit], [Service] and [Install] differently. [Unit] holds metadata and ordering (Description, After), [Service] holds everything about how the process actually runs, and [Install] is only consulted when you run systemctl enable — it is what wires the unit into a target like multi-user.target so it starts on boot.

After=network.target is worth understanding rather than cargo-culting. It only controls ordering — it makes systemd start this unit after the network stack is up — it does not make systemd wait for a working network connection or a resolvable DNS name. A service that needs the network to actually be usable, not just present, should depend on network-online.target and add Wants=network-online.target alongside it.

Type=simple, which this generator always uses, tells systemd to consider the service started the instant it forks the process named in ExecStart. That is correct for the overwhelming majority of modern daemons, including anything written in Node, Python or Go that does not fork itself. Older-style daemons that fork into the background and exit their initial process need Type=forking instead, or systemd will consider the service dead the moment the parent exits.

The restart policy and RestartSec work together to control how systemd reacts to a crash. Restart=on-failure only restarts when the process exits with a non-zero code or is killed by a signal — a clean, intentional exit is left alone. Restart=always restarts unconditionally, including after a normal exit, which is rarely what you want for anything that is supposed to run once and stop. RestartSec is the pause before each restart attempt; without it, a service that crashes instantly on every start can spin in a tight restart loop and pin a CPU core.

Environment variables set with Environment= are only visible to this one process tree, which is exactly the isolation you want — they do not leak from a shell’s ~/.bashrc or profile the way they might for an interactively-started process, and a service’s env is never affected by whoever happens to be logged in. For a large number of variables, or values that should not sit in a world-readable unit file, use EnvironmentFile=/etc/myapp/env instead and point it at a file with tighter permissions.

After editing any unit file, systemctl daemon-reload is not optional — systemd caches unit definitions, and without the reload it keeps running against the old file while systemctl status shows you the new one, which is a common source of “I changed it but nothing happened” confusion.

Frequently asked questions

Where should I save the generated file?

/etc/systemd/system/<name>.service for a system-wide service you manage by hand. Packages that install their own units use /usr/lib/systemd/system/ instead — avoid editing those directly, since a package update can overwrite them; use a drop-in override or a file in /etc/systemd/system/ to take precedence.

Why isn’t my service starting after I edited the unit file?

Almost always because systemctl daemon-reload was skipped. systemd reads unit files once and caches them; editing the file on disk does not update the running definition. Run systemctl daemon-reload, then systemctl restart <name>.

What is the difference between Restart=on-failure and Restart=always?

on-failure restarts only when the process exits with a non-zero status or is killed by a signal. always restarts no matter how the process exits, including a normal, intentional exit code 0. For long-running daemons, on-failure is almost always the correct choice.

Why did I use an absolute path in ExecStart?

Because systemd does not start your process through a login shell, so it never sources ~/.bashrc or /etc/profile and has no populated PATH to search. A bare command name that works fine when you type it in a terminal will fail with “command not found” when systemd tries to run it — always use the full path to the binary.

Should I put secrets directly in Environment= lines?

Avoid it for anything sensitive — unit files under /etc/systemd/system/ are commonly world-readable. Use EnvironmentFile= pointing at a separate file with chmod 600 permissions, or a secrets manager, so credentials are not sitting in a file every local user can read.