Service: Explanation & Insights
Not a program, but the system's contract to keep one running, restart it, and start it at boot.
What It Is
A service is a daemon — or a one-off task — that an init system supervises on your behalf. The word names the management, not the program. The process doing the work (the web server, the database, your app) is the daemon; the service is the wrapper the system puts around it so you can say "start it," "stop it," "start it every boot," "restart it if it crashes," and "show me its logs" — without knowing or caring how the program detaches from a terminal or writes a PID file.
This is the distinction the whole page hangs on, because almost nobody states it cleanly: a daemon is the thing running. A service is how the system manages that thing. On a modern systemd box the two come bundled — you define a service, systemd starts the daemon inside it — so people use the words interchangeably. But they're different layers. "Is the daemon alive?" is a question about a process. "Is the service enabled?" is a question about configuration. Mixing them up is the source of the single most common confusion on Linux, and we'll clear it up below.
On systemd, a service is defined by a unit file — a small .ini-style text file, usually myapp.service, that tells the system what to run and how to babysit it. You manage it with systemctl and read its logs with journalctl. That trio — unit file, systemctl, journalctl — is most of day-to-day Linux server administration, and once it clicks, running services stops feeling like guesswork.
Why It Matters
Before the init system did this for you, "keeping a program running" was a pile of folklore: start it with nohup, background it, write a shell script to start it at boot, hope nothing crashes, and when it inevitably does, notice some hours later when a customer complains. The service abstraction replaces all of that with a contract. You declare what should be true — "this program should be running, and should come back if it dies" — and the system makes it true and keeps it true. That shift, from "I ran the program" to "the system guarantees the program runs," is the entire reason services exist.
It matters for uptime most of all. The most common way a "server goes down" isn't the hardware — it's a service that stopped: a daemon crashed, hit an out-of-memory kill, or failed to come back after a config change. A properly configured service with auto-restart turns most of those from an outage into a half-second blip nobody notices. A badly configured one — or a program someone left running in a screen session instead of as a real service — turns a single crash into a midnight page. Whether your programs run as proper services is, very directly, whether your server stays up. See service down for the diagnose-and-fix when one doesn't.
Enabled vs Active — The One Everybody Confuses
Stop here, because this is the muddy thing this page exists to make permanently clear. A service has two completely independent states, and they answer two different questions:
- active = is it running right now? An
activeservice has a live daemon on the box this very second.inactivemeans it's stopped — no process running. - enabled = will it start automatically at the next boot? An
enabledservice is wired into the boot sequence.disabledmeans it won't start on its own when the machine reboots.
These do not imply each other, and that's exactly what trips people. A service can be:
- enabled but inactive — configured to start at boot, but not running now (you stopped it, or it crashed). It will come back on reboot.
- active but not enabled — running right now, but you started it by hand and it will not survive a reboot. This is the classic, painful one.
That second case is the trap that bites everyone once. You install a database, run systemctl start mysql, test it, everything works, you move on. Three weeks later the server reboots for a kernel update and the database doesn't come back — because you started it but never enabled it. The fix is one word you forgot:
systemctl enable --now myapp.service # enable (at boot) AND start (now), in one command
The --now is the bridge: it does both states at once. Without it, enable only touches the boot wiring (the service won't start until the next reboot) and start only touches the current state (it won't survive one). Internally, enable just creates a symlink so the boot target pulls your unit in — that's all "enabled" physically is — while active is the live truth about a running process. Two switches, two purposes. Burn this in and you've sidestepped the most common Linux gotcha there is.
Pro Tip
When you set up a service you want to survive reboots, use
systemctl enable --now myapp.serviceand make a habit of it. The number of "but it was working yesterday!" mysteries that turn out to be "active but never enabled, then the box rebooted" is genuinely large. One flag, one less 3 a.m. surprise.
How I Manage It
The verbs are the same on every systemd box, which is most of the point — you stop memorizing per-program init scripts and learn one vocabulary:
systemctl status myapp.service # is it alive? when did it start? last log lines?
systemctl start myapp.service # start it now
systemctl stop myapp.service # stop it now
systemctl restart myapp.service # stop then start (the reach-for-it fix)
systemctl reload myapp.service # re-read config without dropping connections (if supported)
systemctl enable myapp.service # start it automatically at boot (just the wiring)
systemctl disable myapp.service # don't start it at boot
systemctl enable --now myapp.service # enable AND start, together
The .service suffix is optional in practice — systemctl status nginx works because systemd assumes .service when you don't say otherwise — but it's worth knowing it's there, because services are only one type of unit (there are also timers, sockets, mounts, and targets).
The first command, status, is the one I run constantly, and reading it well is a skill. A healthy service looks like this:
● nginx.service - A high performance web server
Loaded: loaded (/etc/systemd/system/nginx.service; enabled; preset: enabled)
Active: active (running) since Sat 2026-06-13 09:14:22 UTC; 1 day ago
Main PID: 1204 (nginx)
Tasks: 5 (limit: 9830)
Memory: 12.4M
CGroup: /system.slice/nginx.service
├─1204 nginx: master process
└─1207 nginx: worker process
Here's the order I read it in. The colored dot and Active: line first — active (running) is what I want; failed is a problem, inactive (dead) means stopped. Then the Loaded: line, because it quietly tells me the enabled state in parentheses — enabled here, so this survives a reboot (and right there, the two states from the section above, both on one screen). Then Main PID: to get the process ID if I want to dig with top or ps. The CGroup: block at the bottom is a small gift: systemd tracks every process the service spawned in its own cgroup, so even if the daemon forks a dozen children, they're all accounted for here — no escapees, no orphans hiding from the supervisor. And the last few log lines (systemd appends them under status) are often enough to see why a service is unhappy without even opening journalctl.
For the full logs, journalctl scoped to the unit:
journalctl -u myapp.service # everything this service has logged
journalctl -u myapp.service -f # follow live (like tail -f)
journalctl -u myapp.service -b # just this boot
This is the modern replacement for hunting through files in /var/log. Because a modern service runs its daemon in the foreground and lets systemd capture stdout, the logs land in the journal automatically — the program doesn't even have to know how to write a log file.
Anatomy of a Unit File
A service is defined by its unit file, and they're refreshingly small. Here's a complete, real-shaped one for a foreground program:
[Unit]
Description=My application server
After=network.target
[Service]
Type=simple
ExecStart=/usr/local/bin/myapp --port 8080
Restart=on-failure
RestartSec=5
User=myapp
[Install]
WantedBy=multi-user.target
Reading it top to bottom:
[Unit]— metadata and ordering.After=network.targetmeans "don't start me until the network is up." This is how services express dependencies — you declare what must come first, and the init system works out the order, starting independent services in parallel (which is a big reason systemd boots faster than the old serial scripts).Type=simple— the modern default: "my program does not fork; the process I start is the daemon, track it directly." (ContrastType=forkingfor legacy daemons that detach themselves the old-fashioned way — see the daemon page for that whole story. New programs should besimple.)ExecStart=— the actual command. Note there's no&, nonohup, no backgrounding — you give systemd a plain foreground program and let it be the daemon-maker.Restart=on-failure— the line that earns its keep. If the program exits with an error or gets killed, systemd restarts it.RestartSec=5waits five seconds first (so a program that crashes instantly doesn't spin in a tight restart loop). Other values:Restart=always(restart even on clean exit),Restart=no(the default — don't). For anything that's supposed to stay up,on-failureis the sane choice.User=myapp— run the daemon as an unprivileged user, not root. A service that doesn't need root shouldn't have it; one config line and a crash or compromise is contained.[Install]—WantedBy=multi-user.targetis whatsystemctl enableacts on: it creates the symlink that pulls this service into the normal boot. This section is only about the enabled state — it does nothing until youenable.
Note
A service doesn't have to be a long-running daemon.
Type=oneshotunits run a command once and exit — a filesystem-setup step, a migration, a backup. They still get the same management, dependencies, and logging; they just aren't expected to keep running. So "service" is genuinely broader than "daemon": every daemon-under-systemd is a service, but not every service is a daemon.
The Opinion: Run It as a Service, Full Stop
Here's the prescriptive bit, and it's not a close call. When you have a long-lived program to run on a server, run it as a systemd service — a foreground program with a small unit file — not as a hand-detached daemon and absolutely not as nohup ./myapp & in a screen session you'll forget about.
The reasoning is all upside. Write the unit file once and you get, for free: it starts at boot (enable), it restarts when it crashes (Restart=on-failure), its logs are captured and queryable (journalctl -u), every child process it spawns is tracked in a cgroup so nothing escapes, it can drop privileges (User=), and the next person — including future you — manages it with the exact same three commands as every other service on the box. The nohup-in-a-screen approach gives you none of that: no boot persistence, no auto-restart, logs dumped into a nohup.out wherever you happened to be standing, and a process nobody can find six months later. The effort difference is about six lines of .ini. There is no scenario on a server where the screen approach is the right answer — if you catch yourself reaching for it, that's the sign you want a unit file instead.
Gotchas
- Active but not enabled — the big one, covered above: it's running now, but won't survive a reboot. Always check the
Loaded:line's parentheses, or just useenable --now. stopis notdisable— stopping a service ends it now but leaves it enabled, so it comes back on reboot. Disabling it prevents the boot start but doesn't stop the running copy. They're orthogonal, like theirstart/enableopposites. If you truly want a service gone, you usually want both:systemctl disable --now myapp.service.- Edit a unit file, then
daemon-reload— systemd caches unit files in memory. After editingmyapp.serviceyou must runsystemctl daemon-reloadbeforerestart, or systemd keeps running the old definition and you'll swear the edit didn't take. (Usesystemctl editand it reloads for you.) statusshows logs, but only a few lines — the tail understatusis a teaser. When a service isfailed, read the full story withjournalctl -u myapp.service -e; the real error is often above the linestatuschose to show.reload≠restart—reloadasks a service to re-read its config without dropping connections (great for a web server under load);restartkills and re-launches it (a brief outage). Not every service supportsreload;statusand the unit file tell you. Reach forreloadwhen you can,restartwhen you must.- The legacy
servicecommand still works — on systemd boxes,service nginx restartis quietly translated intosystemctl restart nginx. It's a compatibility shim from the sysvinit era. Usesystemctldirectly; you'll want its richer output anyway.
History and Philosophy
For most of Unix's life, "a service" wasn't a first-class thing — it was a convention. sysvinit gave you /etc/init.d/ scripts: a shell script per service that knew how to start, stop, and restart its daemon, invoked in a fixed order set by runlevel. The service command and the symlink farms under /etc/rc?.d/ were the management surface. It worked, but every script was hand-written, subtly different, boot was strictly serial (and slow), and crucially nothing watched the daemon after it started. If it died, it stayed dead until a human noticed.
Upstart (Ubuntu, mid-2000s) took the first real swing at fixing this with an event-driven model, and then systemd (around 2010) reframed the whole idea — controversially, loudly, and ultimately across nearly every major distribution. Its central move was declarative supervision: you stop writing a script that does the starting and instead write a description of the desired state — what to run, what it depends on, when to restart it — and let PID 1 figure out how to make that true and keep it true. Parallel boot, dependency resolution, per-service cgroups, captured logs, and auto-restart all fell out of that one shift in thinking.
The deeper philosophy is worth a moment, because it's the same idea that powers Kubernetes and the whole cloud: don't tell the computer how to keep your program running, tell it what running looks like and let it reconcile reality toward that. A unit file is a tiny declaration of intent; systemd is the loop that keeps reality matching it. Once you see services that way — as a promise the system makes and keeps, not a script you run and abandon — the entire model stops feeling like incantation and starts feeling like exactly what you'd have designed yourself, if you'd had to babysit ten thousand daemons and gotten tired of it.
See Also
- daemon — the background process a service manages; daemon = the runner, service = the management
- systemd — the init system that turns unit files into running, supervised services
- init-system — the broader role: PID 1 starting and supervising everything
- process — what's actually running when a service is
active - pid — the
Main PIDinsystemctl status, your handle on the live process - cgroup — how a service accounts for every child process it spawns
- sysvinit — the shell-script ancestor of declarative services
systemctl— the one command for start, stop, enable, restart, statusjournalctl— read the logs systemd captures from a serviceservice— the legacy command, now a shim oversystemctlnohup— what people use instead of a service, and why you shouldn't- service down — the walkthrough for when a service that should be running isn't
Did a service you depend on quietly stop running?
CleverUptime detects the services running on your server from
/procand flags the moment one that should be up has gone away — so a stopped service reaches you as an alert, not as an outage.Want to see your own server's health right now? One command, no signup, no install.