01What systemd Is Actually Managing
When Linux boots, systemd is the first process the kernel hands control to — PID 1. Everything else — your network stack, your display manager, your database — comes up because systemd reads a collection of small configuration files called unit files and acts on them in the right order. A unit file is not code. It is a declarative INI-style text file that says: here is a thing, here is how to start it, here is what it needs before it can run.
What a unit file actually is, how to write one, and how to make your own script start on boot and restart when it dies.
Unit files live in a few places. Packages drop theirs into /usr/lib/systemd/system/. You write yours into /etc/systemd/system/ — that directory wins over the system one for any file with the same name, which is how you override a package's service without touching files that will be clobbered on the next update. The file extension tells systemd what kind of unit it is: .service for a process, .timer for a scheduled job, .socket for socket activation. Today, we care about .service.
02Anatomy of a Real Unit File
Here is a minimal but complete service file — the kind you would write to run a custom script or small server:
[Unit] Description=My Sync Script After=network-online.target Wants=network-online.target
[Service] Type=simple ExecStart=/usr/local/bin/my-sync.sh Restart=on-failure RestartSec=10s User=syncuser WorkingDirectory=/opt/sync
[Install] WantedBy=multi-user.target
Walk through each section. [Unit] holds metadata and ordering. After= tells systemd not to start this service until network-online.target is reached — meaning the network is up and configured, not merely that NetworkManager has started. Wants= is a softer dependency: the target will be pulled in if possible, but a failure there will not abort your service.
[Service] is where the process itself is described. Type=simple means systemd considers the service started the moment ExecStart launches — correct for a script or long-running process that does not fork. If your program forks into the background and writes a PID file, use Type=forking instead. Restart=on-failure is the line that makes the service self-healing: if the process exits with a non-zero status, systemd will restart it after the RestartSec delay. Running the service as a dedicated low-privilege user with User= is good hygiene — do not run custom services as root unless there is a concrete reason.
[Install] controls what happens when you enable the unit. WantedBy=multi-user.target means: when the system reaches the normal multi-user runlevel, pull this service in. Without this section, you can start the service manually but it will not survive a reboot.
03The Four Commands You Actually Need
Drop your file into /etc/systemd/system/my-sync.service, then:
sudo systemctl daemon-reload
sudo systemctl enable --now my-sync.servicedaemon-reload is not optional — systemd reads unit files at load time and does not notice new files until you tell it to. enable --now both enables the unit (creates the symlinks that hook it into the boot target) and starts it immediately in the same step.
From there, two more commands cover almost everything:
sudo systemctl status my-sync.service # is it running, and what happened last time
sudo systemctl restart my-sync.service # restart it manually
sudo journalctl -u my-sync.service -f # follow its logs in real timejournalctl -u filters the journal to just that unit — invaluable when a service is flapping and you need to see why. Add -b to limit output to the current boot, or -n 50 for just the last fifty lines.
One common trap: if your ExecStart path is wrong or the script is not executable, the service will fail immediately and Restart=on-failure will keep trying every ten seconds. systemctl status will tell you exactly that in plain English, and journalctl will show the error output. Read those two first before reaching for anything else.
That is genuinely all it takes. One file, four commands, and your script runs at boot, logs to the journal, and comes back up on its own when something goes wrong.
The players
/etc/systemd/system/
Reference
user-managed unit file directory, overrides package defaults
/usr/lib/systemd/system/
Reference
package-managed unit file directory
