Your web server ran fine all afternoon. The machine rebooted for a kernel update, and it never came back. Nothing crashed, no file is corrupt. You started the service by hand once and never told the init system to bring it back at boot.
$ systemctl status nginx
○ nginx.service - A high performance web server and a reverse proxy server
Loaded: loaded (/lib/systemd/system/nginx.service; disabled; preset: enabled)
Active: inactive (dead)
Two words in that output carry the whole story: disabled and inactive. One is about right now. The other is about every boot from here on. The tool that reads them and controls them is systemctl, your front end to systemd. systemd is process ID 1, the first thing the kernel starts, and the parent of nearly everything else running on the box.
systemd is the init system on almost every mainstream distro now: Debian, Ubuntu, RHEL, Rocky, AlmaLinux, Fedora, SUSE. It starts services at boot, restarts them when they die, keeps their logs, and hands you one command,
systemctl, to drive all of it. Learn six verbs, plus journalctl for the logs, and you can run a server.Two people are reading that failed status. A recent passout who has only ever clicked Start in a graphical panel, and an admin with forty boxes who wants the correct habit so a service never silently misses a reboot again. Both need the same two ideas kept apart, so we start there.
start and enable make two different promises
This is the single idea that trips up more beginners than anything else about systemd, so it gets the most room. start and enable sound like synonyms. They are not, and mixing them up is exactly how a service goes missing after a reboot.
start runs it right now
Starting a service launches it this instant and nothing more. If the machine reboots, systemd has no memory that you ever wanted it. Stopping is the mirror image: it kills the running copy now and says nothing about the future.
enable brings it back at every boot
Enabling does not start anything today. It writes a symlink into the boot target so that next time systemd comes up, it launches the service on its own. That is why a freshly enabled service can still show inactive until you also start it, and why a running service you forgot to enable vanishes on reboot. The verb that does both in one move is enable --now.
$ sudo systemctl start nginx # start the service now
$ sudo systemctl stop nginx # stop it now
$ sudo systemctl restart nginx # stop then start
$ sudo systemctl reload nginx # reread config, keep serving
$ sudo systemctl enable nginx # start automatically at boot
$ sudo systemctl disable nginx # do not start at boot
$ sudo systemctl enable --now nginx # enable and start together
| Command | What it does | Survives reboot? |
|---|---|---|
start | Runs the service now | No |
enable | Marks it to launch at boot | Yes |
restart | Stops then starts | No change |
reload | Rereads config without dropping connections | No change |
enable --now | Enables and starts in one command | Yes |
A service that was started but never enabled works perfectly until the next reboot, then it is simply gone. Nobody changed anything, which is what makes it maddening to chase. On any service that must stay up, run
systemctl is-enabled name before you walk away. If it says disabled, you are one power cut from an outage.Reading systemctl status line by line
The status output looks busy, but only a few lines matter. Here is a healthy service.
$ systemctl status nginx
● nginx.service - A high performance web server and a reverse proxy server
Loaded: loaded (/lib/systemd/system/nginx.service; enabled; preset: enabled)
Active: active (running) since Fri 2026-07-03 09:14:22 UTC; 2min 5s ago
Main PID: 1421 (nginx)
Tasks: 3 (limit: 4630)
Memory: 5.6M
CGroup: /system.slice/nginx.service
├─1421 nginx: master process /usr/sbin/nginx
├─1422 nginx: worker process
└─1423 nginx: worker process
The colored dot tells you at a glance: a filled dot means active, a hollow dot means inactive, and a red dot means failed. The Loaded line names the unit file and, in the same breath, whether it is enabled. The Active line is the runtime truth, with an uptime you can read. Main PID ties the service back to a real process, the same number ps and top would show you from Part 7. The CGroup block lists every process systemd counts as part of this service, which is how it can stop all of them cleanly instead of leaving orphans behind.
When you only want a yes or no, ask directly. These two return a single word and an exit code, which is what you want inside a script.
$ systemctl is-active nginx
active
$ systemctl is-enabled nginx
enabled
Never edit the file in /lib. Use a drop-in.
Plenty of tutorials tell you to open /lib/systemd/system/nginx.service and change a line. Do not. That file belongs to the package, and the next update overwrites it, taking your change with it. Here is the verdict I stand by: touch a vendor unit file directly and you have planted a bug that detonates on a future apt upgrade. The supported way is a drop-in, and systemctl edit creates one for you.
$ sudo systemctl edit nginx
# opens an editor and creates:
# /etc/systemd/system/nginx.service.d/override.conf
# put only the lines you want to change:
[Service]
Restart=always
RestartSec=3
systemd loads the original unit first, then merges your override on top. Anything under /etc wins over anything under /lib, which is the whole point: your change lives in a file the package manager will never touch. Save it, tell systemd to reread its files, and restart so the new setting takes hold.
$ sudo systemctl daemon-reload # only needed if you edited by hand
$ sudo systemctl restart nginx
$ systemctl cat nginx # shows the unit plus every override
If you used systemctl edit, it runs daemon-reload for you on save. If you wrote the file with a plain editor instead, systemd has not noticed it yet, and daemon-reload is the step everyone forgets. A unit file has three sections worth knowing.
| Section | Common directives | Answers the question |
|---|---|---|
[Unit] | Description, After, Requires | What must be up first |
[Service] | ExecStart, Restart, Type | How to run it and recover it |
[Install] | WantedBy | Which target enable hooks it into |
That last row is why enable works at all. When you run systemctl enable nginx, systemd reads WantedBy=multi-user.target and drops a symlink into that target so the service comes up with everything else at boot.
When a unit will not start
You just dropped a new unit file in place and systemd claims it does not exist.
$ sudo systemctl start myapp
Failed to start myapp.service: Unit myapp.service not found.
$ sudo systemctl daemon-reload
$ sudo systemctl start myapp
Nine times out of ten the fix is daemon-reload: systemd caches its unit files and will not see a brand new one until you tell it to look again. The tenth time it is a typo in the unit name. When the service starts but then dies, stop guessing and read its own log with journalctl, filtered to that unit.
$ journalctl -u nginx -b # this unit, this boot only
$ journalctl -u nginx -f # follow new lines live
$ journalctl -u nginx --since "10 min ago"
The truncated log at the bottom of systemctl status is a preview, not the whole story. When something is wrong, journalctl -u name -b is the command that actually earns its keep. We take the journal apart properly in Part 10. If you are coming to Linux services from a virtualization or cloud background, the same idea about a control plane starting and supervising workloads shows up in the VMware for Beginners and Cloud for Beginners guides.
What actually slows your boot
systemd starts most services in parallel, which is why boots are fast. When a boot is slow, it hands you the numbers to find out why.
$ systemd-analyze
Startup finished in 3.812s (kernel) + 12.431s (userspace) = 16.243s
graphical.target reached after 12.210s in userspace.
$ systemd-analyze blame
8.700s NetworkManager-wait-online.service
2.883s docker.service
2.201s snapd.service
1.204s systemd-journal-flush.service
0.541s apt-daily.service
Here is where I part ways with most advice, which stops at blame. blame ranks units by how long each took to initialize, but a slow unit that ran in parallel with everything else may have delayed nothing. It also skips services of Type=simple entirely, because systemd considers them started the instant it forks them. The command that tells you what really held up the finish line is critical-chain.
$ systemd-analyze critical-chain
graphical.target @12.210s
└─multi-user.target @12.205s
└─docker.service @9.320s +2.883s
└─network-online.target @9.180s
└─NetworkManager-wait-online.service @0.410s +8.700s
Read the tree from the bottom up. The @ is when a unit became active and the + is how long it took. Here 8.7 seconds of a 16 second boot went to one service waiting for the network to declare itself online, and because docker is ordered after network-online.target, everything downstream sat and waited too. On a server that never needs the network up before login, disabling NetworkManager-wait-online reclaims those seconds. blame would have pointed at the same service, but only critical-chain proves it was actually on the path that mattered.
"What is the difference between
systemctl enable and systemctl start?" Say it plainly: start runs the service now, enable makes it come up at boot by linking it into a target, and neither one implies the other. Land it with the shortcut: enable --now does both. Interviewers ask this because the wrong answer is the exact mistake that causes a service to disappear after a reboot.Pick a harmless service such as
chronyd (or cron on Debian) and run sudo systemctl enable --now chronyd. Reboot, then confirm it came back on its own:systemctl is-enabled chronyd && systemctl is-active chronydTwo lines of
enabled and active mean you did it right. Now run sudo systemctl disable --now chronyd and reboot again to watch it stay down.Making one service wait for another
Here is a failure you will meet on real servers. Your application boots faster than the database it talks to, so it comes up, cannot reach Postgres, and dies before Postgres is ready. On a fast laptop it looks fine because timing happens to line up. On a loaded server it fails every few reboots. systemd has two separate knobs for this, and treating them as one knob is the mistake.
After= controls order only: start that other unit first. Requires= controls dependency: pull that unit in, and if it dies, take mine down with it. Wants= is the soft version of Requires, so pull the other unit in if you can but do not fail me when it is missing. Ordering and requirement are different axes, which is exactly the part people get wrong.
$ sudo systemctl edit myapp
# /etc/systemd/system/myapp.service.d/override.conf
[Unit]
After=postgresql.service
Requires=postgresql.service
With both lines present, systemd starts Postgres first and refuses to keep your app up if Postgres fails. Set only After= and you get the order but no safety net: if Postgres never starts, your app still launches straight into a wall. Set only Requires= and systemd may start both at the same instant, which is the subtle bug that looks fixed on a quick machine and breaks under load. In practice you pair them.
| Directive | Controls order? | Fails you if the other fails? |
|---|---|---|
After= | Yes | No |
Requires= | No, on its own | Yes |
Wants= | No, on its own | No |
Most well written units use Wants= plus After= for optional helpers and save Requires= for the handful of dependencies that genuinely cannot be missing. Reach for Requires= too freely and one flaky dependency starts dragging healthy services down with it.
Common questions
Do I need daemon-reload every time? Only after you add or hand-edit a unit file. Plain start, stop and restart do not need it. systemctl edit runs it for you.
What is the difference between disable and mask? Disable stops a service from starting at boot but you can still start it by hand. Mask links it to /dev/null so it cannot start at all, by boot or by hand, until you unmask it. Mask is the hard off switch.
Should I use kill on a service? No. kill hits one process, but a service is a whole cgroup of them, covered back in Part 7. Use systemctl stop so systemd shuts down every process it owns.
restart or reload after a config change? Prefer reload when the service supports it, because it rereads config without dropping live connections. Fall back to restart only when reload is not offered.
How do I see everything that is running? systemctl list-units --type=service --state=running for what is up now, and systemctl list-unit-files --type=service for what is installed and whether each is enabled.
Get these habits into your fingers and services stop being mysterious. You start it, you enable it, you check status, and when it misbehaves you read its journal instead of guessing. Next up is Part 10, where journalctl stops being a single flag and becomes a real investigation tool. Working through the whole path? The Linux for Beginners complete guide lists every part in order.
References
• systemctl(1) manual page
• journalctl(1) manual page
• systemd-analyze, blame and critical-chain
• systemd.unit, drop-in override files


DrJha