service Command: Tutorial & Examples

The universal remote for background programs — start, stop, and check daemons without caring which init system you're on.

What It Is

service is the friendly, forgettable little command you reach for when you want to start, stop, restart, or check on a background program — a daemon like your web server, your database, or sshd. You type something close to plain English — service nginx restart — and the thing you wanted to happen, happens. No flags to memorize, no syntax to look up. It reads like a sentence, which is exactly why it has survived for twenty years while everything underneath it changed twice.

And here's the secret this whole page is built around: service doesn't actually do anything. It's a thin shell script — a go-between — that turns your friendly request into whatever the real machinery of this particular server happens to understand. On an old box that means an init script; on a modern box it quietly calls systemctl for you. That indirection is the entire trick, and once you see it, a confusing corner of Linux snaps into focus. We'll explain every command it takes, show you the real script doing the translation, and by the end you'll know not just how to use it but why it still works everywhere — and when to stop using it.

Your First Look

A daemon is just a program that runs quietly in the background with no terminal attached — the web server answering requests, the database holding your data, the SSH server waiting for you to log in. They need to be started at boot, stopped for maintenance, and checked when something's wrong. service is the verb for all of that. The shape is always the same — a noun, then a verb:

service SERVICE COMMAND

So, to check whether the cron daemon is alive (this only looks, it changes nothing):

service cron status
● cron.service - Regular background program processing daemon
     Loaded: loaded (/usr/lib/systemd/system/cron.service; enabled; preset: enabled)
     Active: active (running) since Sat 2026-05-09 17:40:24 CEST; 3 weeks 4 days ago
   Main PID: 1394 (cron)
      Tasks: 1 (limit: 37810)
     Memory: 2.6M (peak: 6.1M, swap: 224K, swap peak: 788K)

Pause on that output for a second, because it's the first clue to everything below. You asked service for a status, and what came back is unmistakably the output of systemctl status — the green dot, "Loaded", "Active (running)", a PID, even a memory figure. You didn't type systemctl. You typed service. Something in the middle did the translation for you, and it did it so cleanly you'd never know — unless you went looking. We're about to go looking.

How It Works: The Universal Remote

Here is the one idea that makes service make sense, and it's the thing every other tutorial leaves muddy. Linux has had, over the years, more than one system for managing background programs — and they speak completely different languages.

For the first few decades, the answer was SysV init (named for Unix System V, 1983). Every service shipped a shell script in /etc/init.d/, and you ran it by hand: /etc/init.d/nginx start. Each script was a little hand-written program that knew how to launch and kill its own daemon. It worked, but it was the wild west — every script different, no real supervision, a service that crashed at 3am just stayed crashed.

Around 2014, the major distributions switched to systemd, a far more capable manager that watches services, restarts them when they die, tracks their resource use, and starts them in parallel at boot. systemd's native command is systemctl, and its services are declared in unit files, not shell scripts. A completely different world.

So now imagine you're a person — or a script, or a piece of documentation — who learned service nginx restart in 2010. Should that muscle memory break the day the server upgrades to systemd? No. And it doesn't, because of service. It is a compatibility shim: a stable, friendly front door nailed over whatever init system happens to live behind it. You knock the same way every time; service figures out who's actually home and forwards your knock to them.

Note

This is a recurring pattern in well-designed systems: a stable interface over a changing implementation. The phone number stays the same even after they replace the whole switchboard behind it. service is that phone number for daemons — which is exactly why decades of tutorials, Stack Overflow answers, and shell scripts still work on a brand-new box.

Watching the translation happen

You don't have to take my word for any of this, because service is not a compiled binary you have to trust blindly — it's a plain, readable shell script sitting at /usr/sbin/service. Open it and the whole magic trick is right there in the open. The heart of it is this decision, made the instant the command runs:

if [ -d /run/systemd/system ]; then
   is_systemd=1
fi

That's it — that's how service knows which world it's in. If the directory /run/systemd/system exists, systemd is the boss of this machine (it creates that directory at boot), and is_systemd gets set. From there the script becomes a translator, rewriting your friendly verb into the equivalent systemctl call and then handing over completely:

if [ -n "$is_systemd" ]
then
   UNIT="${SERVICE%.sh}.service"
   case "${ACTION}" in
      restart|status|try-restart)
         exec systemctl ${ACTION} ${UNIT}
      ;;
      ...

Look at that exec — it's the whole story in one keyword. exec doesn't call systemctl and wait for it; it replaces the service process with systemctl entirely, body-snatcher style. The service script stops existing and systemctl takes over its place in the process table. That's why the status output you saw earlier was pure systemctl, byte for byte: by the time you saw it, service was already gone. It introduced you to systemctl and quietly left the room.

And if there's no systemd? The script falls through to its other half and runs the old init script directly, the 1983 way:

exec env -i ... "$SERVICEDIR/$SERVICE" ${ACTION} ${OPTIONS}

One command, two completely different engines underneath, and you never had to know which. That is the universal remote.

The Commands, Explained

service itself defines almost no vocabulary — it passes your verb straight through to the init script or systemctl. But these are the ones that work essentially everywhere, because every well-behaved service supports them:

  • start — launch the daemon. service nginx start. Idempotent in spirit: starting an already-running service is harmless.
  • stop — shut it down gracefully (sends a polite termination signal and waits). The daemon gets to finish in-flight work and clean up.
  • restartstop then start, full stop. A hard bounce: the process you were running is gone and a new one takes its place. Use this when a config change needs a clean slate, or when the service is wedged.
  • reload — re-read the configuration without dropping the process or its connections. Far gentler than restart — your live SSH sessions and open database connections survive. Always prefer reload if the service supports it; not all do (it falls back to the init script if systemd reports the unit can't reload).
  • status — the read-only one. Is it running? Since when? What PID? On systemd you get the rich dashboard you saw above; on SysV you get whatever the script chooses to print. This is the safe one to poke at freely — it never changes anything.
  • try-restart — restart only if it's already running; do nothing if it's stopped. Handy in upgrade scripts that shouldn't accidentally start a service the admin had deliberately turned off.
  • force-reload — reload if the service can; otherwise fall back to a full restart. "Get my new config live by whatever means necessary."

And a few that service itself implements (not pass-throughs):

  • --status-all — the bird's-eye view of every SysV service at once. More on this below; it's genuinely useful and has one sharp edge.
  • --full-restartstop then start run as two separate invocations of the init script. On systemd it just becomes a plain restart (a systemd restart is already a full one), so you'll mostly meet this on legacy boxes.
  • force-stop — on systemd, this maps to systemctl --signal=KILL kill: the impolite shutdown. No graceful wind-down, just SIGKILL. The equivalent of yanking the power cord; reach for it only when stop hangs.

Pro Tip

reload is the unsung hero of running a server. restart drops every connection the moment you hit Enter — fine for your hobby box, a small outage on a busy one. reload slides the new config in under a running daemon and nobody on the other end feels a thing. The reflex to build: try reload first, fall back to restart only if it complains.

The Bird's-Eye View: --status-all

This one earns its own section because it's the closest service comes to a dashboard. Run it and you get one line per SysV service, with a little glyph telling you the state at a glance:

service --status-all
 [ + ]  apparmor
 [ - ]  anacron
 [ + ]  cron
 [ - ]  cryptdisks
 [ + ]  cups
 [ + ]  dbus
 [ + ]  mysql
 [ + ]  networking
 [ + ]  ssh
 [ - ]  rsync
 [ - ]  sysstat

The glyphs read like a traffic light:

  • [ + ] — running. All good.
  • [ - ] — installed but not running (stopped, or never started).
  • [ ? ] — the script has no status command, so service honestly shrugs: it can't tell. Not an error — just "this old script never bothered to implement a way to ask."

Here's the sharp edge, and it's a classic first-timer trap: --status-all only knows about SysV init scripts in /etc/init.d/. A modern service that exists purely as a systemd unit — with no legacy init script at all — simply won't appear in this list. So a service can be merrily running and yet be absent from service --status-all, which panics people into thinking it's missing. It isn't; you're just looking through the old window at the new world. The honest, complete inventory on a systemd box comes from systemctl list-units --type=service.

Warning

Don't treat service --status-all as the full picture of what's running on a modern server. It lists only services that still ship an /etc/init.d/ script. Pure-systemd daemons (an increasing share every year) are invisible to it. When in doubt, cross-check with systemctl.

How I Use It

Honestly, my hands type service on autopilot, and that's the point — it's the verb that survived every distro upgrade I've lived through, so it never not works. My actual day-to-day with it is small and boring, which is the highest compliment you can pay a sysadmin tool.

When I change a config, my reflex is reload, not restartservice nginx reload after editing a vhost, because it re-reads the file without dropping a single live connection. I only escalate to service nginx restart when reload won't do the job (a port change, say) or when a service has gone catatonic and needs a clean kill-and-relaunch.

When something's wrong and I don't yet know what, service whatever status is the first poke — it's read-only, so I can mash it without fear, and on a systemd box it hands me the last few log lines for free, which is often the entire diagnosis. And when I've just provisioned a fresh box and want a quick "what did the install scripts leave running?", service --status-all gives me the legacy roll-call in one screen — with the caveat above firmly in mind.

But here's the honest part a lot of guides won't tell you: the moment I'm doing anything beyond start/stop/restart/status, I drop the shim and go straight to systemctl. Enabling a service to start at boot? service can't do that at all — that's systemctl enable. Reading why a service died? systemctl status plus journalctl -u. Listing every unit, masking one, checking dependencies? All systemctl. service is the comfortable front porch; systemctl is the house. I live in the house and visit the porch out of habit.

Reading It by Example

Build the instinct with a few real readouts and what each one is telling you:

Active: active (running) in a status → the daemon is up and supervised. The since timestamp is gold: a service that restarted two minutes ago on a box that's been up for weeks is a service that recently crashed and was auto-restarted by systemd — quietly, behind your back. The clock is the tell.

Unit notathing.service could not be found → you asked service about something systemd doesn't know. Either a typo, or — the subtle one — a service that exists only as a SysV init script that systemd hasn't been told to wrap. On a systemd box, service routes status through systemctl, so the error you get is a systemctl error, even though you typed service. Final proof of who's really answering. (Notice the periphery, too: it's a useful tripwire for "is this thing even installed?")

[ ? ] next to a service in --status-all → not broken, just old. That init script predates the convention of supporting a status query, so nobody can ask it how it's doing. Check it the modern way with systemctl status NAME instead.

service foo stop succeeds, but foo is still answering on its port → the foot-gun that the script's authors anticipated. Some services are started on demand by a paired .socket unit; stopping the service alone leaves the socket listening, ready to relaunch it. The service script actually tries to handle this for you (it hunts for socket units that trigger your service and stops them too) — but if you bypassed it with raw systemctl stop foo.service, you'd hit exactly this. A tiny kindness baked into the shim that most people never notice.

Cheat Sheet

The whole tool, at a glance:

  • service NAME status — is it running? (read-only, safe to spam)
  • service NAME start / stop / restart — the big three
  • service NAME reload — apply new config without dropping connections (prefer this)
  • service NAME force-reload — reload, or restart if it can't reload
  • service NAME try-restart — restart only if already running
  • service --status-all — every SysV service at once: [ + ] up, [ - ] down, [ ? ] can't tell
  • service --full-restart NAME — stop-then-start as two passes (legacy boxes)
  • service --version / service --help — version string and the one-line usage

What service cannot do (reach for systemctl):

  • systemctl enable NAME — start at boot (the single most common thing service can't do)
  • systemctl list-units --type=service — the complete inventory, systemd-native services included
  • journalctl -u NAME — read a service's logs to find out why it died

Gotchas

  • service can't enable-at-boot. Starting a service now and starting it every boot are two different things. service redis start runs it this once; close the lid, reboot, and it's gone unless you also ran systemctl enable redis. This trips up nearly everyone exactly once.
  • --status-all is SysV-only. A pure-systemd service that's running fine can be entirely absent from the list. Absence here is not evidence of a stopped service.
  • The output is whatever's underneath. Two boxes, same service x status command, completely different-looking output — because one's relaying SysV and the other's relaying systemd. The shim doesn't normalize the result; it only normalizes the request.
  • It runs with a scrubbed environment. service deliberately wipes almost every environment variable and sets the working directory to / before launching anything, so a service starts in a clean, predictable world rather than inheriting your shell's PATH, aliases, or cd. Helpful and correct — but a source of "it works when I run the script by hand and breaks under service" head-scratching. The fix is to make the service not depend on your personal environment.

History & Philosophy

service came from Red Hat in 2006 (the copyright header still says so, right at the top of the script — Copyright (C) 2006 Red Hat, Inc.), born into the SysV-init era as a tidy wrapper so admins would stop typing /etc/init.d/whatever restart by hand and stop accidentally dragging their messy shell environment into a daemon's launch. Debian and Canonical later adopted and extended it, which is why the script carries a little stack of copyright lines like rings in a tree — Red Hat 2006, Canonical 2008, Debian 2013 — a fossil record of the Linux world passing this useful little tool hand to hand.

Then came the great upheaval. When systemd swept the distributions around 2014, it could have simply broken everyone's muscle memory and every init-management line in every deployment script on earth. Instead — and this is the quietly graceful part — service was kept alive and taught to speak systemd, becoming the bridge between the old world and the new. A command designed to wrap init scripts was repurposed to wrap their replacement, transparently, so that the upgrade was invisible to anyone who only ever said "start," "stop," "restart." There's a real lesson tucked in there about how you retire a beloved interface without a riot: you don't delete it, you teach it to forward the mail.

Which leaves service in a charming, slightly melancholy position today: it's a translator for a language almost everyone now speaks natively. The pros mostly use systemctl directly — but the muscle memory of service nginx restart is so deep across so many millions of fingers that nobody dares remove it, and frankly nobody should. It's the universal greeting that works in every country, even after everyone learned the local tongue. That it still just works on a server installed yesterday is a small monument to the Unix instinct for backward compatibility — and a good thing to admire on your way to learning the tool it now politely defers to.

See Also

  • systemctl — what service calls under the hood; the tool you'll actually grow into
  • journalctl — read a service's logs to find out why it stopped
  • systemd — the manager behind the curtain, explained from zero
  • ps — confirm with your own eyes that the daemon's process is (or isn't) there
  • daemon — what a background service actually is
  • init system — SysV vs systemd, the whole story
  • /etc/init.d — where the old-world scripts live

Stopped a service and aren't sure it actually came back?

CleverUptime detects the daemons running on your box from /proc and tells you in plain language when one that should be up has quietly gone down — so a service that died at 3am and didn't restart doesn't wait until morning to find you.

Want to see your own server's health right now? One command, no signup, no install.

Check your server →