I learned service back before systemctl became the dominant way of doing things, and even now, years into the systemd era, I still find myself typing service out of habit on plenty of systems — and it still works, because on modern distributions it’s become a compatibility shim that forwards to whatever’s actually managing services underneath. Understanding both the command itself and what’s really happening behind it has saved me from real confusion more than once.
What service Actually Does
service is a command that provides a simple, uniform interface for starting, stopping, restarting, and checking the status of system services, regardless of what init system or service manager is actually running underneath. On older SysVinit-based systems, it worked by directly invoking the appropriate script in /etc/init.d/. On modern systemd-based distributions (which is the overwhelming majority of what you’ll encounter today — Ubuntu, Debian, RHEL, Fedora, CentOS all default to systemd), service acts as a wrapper that detects systemd is present and transparently forwards the command to systemctl instead.
I confirmed its basic behavior on my own test system:
service --status-all
[ - ] dbus
[ - ] procps
[ - ] x11-common
That output style (with [ + ], [ - ], or [ ? ] status indicators) is actually the classic SysVinit-style presentation, which service preserves even on systemd systems for backward compatibility with scripts and habits built around the older interface.
Basic Syntax
service <service-name> <command>
Or for the special all-services listing:
service --status-all
Core Commands
Starting a Service
sudo service nginx start
Stopping a Service
sudo service nginx stop
Restarting a Service
sudo service nginx restart
This performs a full stop followed by a start — the service is briefly unavailable during the transition, which matters for anything sensitive to even momentary downtime.
Reloading a Service
sudo service nginx reload
Reload asks the service to re-read its configuration without fully stopping and restarting the process, which for something like nginx means it gracefully finishes handling in-flight connections on the old configuration while spinning up new worker processes with the updated config — no dropped connections, unlike a full restart. Not every service supports reload; it depends on whether the underlying init script or systemd unit defines a reload action.
Checking Status
service nginx status
Shows whether the service is currently running, its process ID, and often recent log output, depending on what’s actually managing the service underneath.
Listing All Services and Their Status
service --status-all
This walks through every service with an init script (or, on pure systemd systems, a compatibility shim’s view of things) and reports its current state.
What’s Actually Happening Underneath on systemd Systems
This is the part that took me a while to fully internalize. On a modern Ubuntu or RHEL system, service nginx restart doesn’t directly manipulate anything — it detects that systemd is the active init system and translates the command into the equivalent systemctl invocation, roughly:
systemctl restart nginx.service
You can verify this translation is happening by checking the service script itself on a systemd-based Debian/Ubuntu system, which contains explicit logic to detect systemd and delegate to systemctl when present, falling back to legacy SysVinit script invocation only for services that don’t have a corresponding systemd unit file.
This matters practically because it means anything you can do with service on a modern system, you can do more powerfully and with more detail directly through systemctl — but service remains genuinely useful for its simplicity, muscle memory, and cross-compatibility with older systems and scripts that predate widespread systemd adoption.
service vs systemctl: When to Use Which
I still use service for the quick, simple, everyday operations — start, stop, restart, status — specifically because the syntax is shorter and I don’t have to remember the .service suffix or think about unit file naming conventions. For anything more advanced, I switch to systemctl directly:
# Enabling a service to start automatically at boot - service can't do this
sudo systemctl enable nginx
# Disabling autostart
sudo systemctl disable nginx
# Viewing detailed status with recent log lines
systemctl status nginx
# Viewing full logs for a service
journalctl -u nginx
# Masking a service (prevents it from being started at all, even manually)
sudo systemctl mask nginx
This is an important limitation to understand: service only controls the current running state of a service, not whether it starts automatically at boot. Enabling/disabling boot-time autostart is exclusively a systemctl (or, on very old SysVinit systems, update-rc.d/chkconfig) responsibility, entirely outside what service itself can do.
Practical Examples Across Common Services
# Web server
sudo service apache2 restart
sudo service nginx reload
# Database
sudo service postgresql status
sudo service mysql restart
# SSH daemon - careful with this one on a remote session!
sudo service ssh restart
# Networking
sudo service networking restart
# Cron daemon
sudo service cron status
I always pause before restarting the SSH service on a machine I’m remotely connected to via SSH — a misconfiguration in sshd_config combined with a restart can lock you out entirely if there’s no other access path. I test configuration validity first wherever the service supports it:
sudo sshd -t # tests sshd config syntax without restarting anything
sudo nginx -t # tests nginx config syntax
Legacy SysVinit Behavior
On genuinely old systems, or containers deliberately built without systemd, service directly executes scripts found in /etc/init.d/:
service nginx start
# roughly equivalent to directly running:
/etc/init.d/nginx start
These init scripts are shell scripts that implement a standard set of actions (start, stop, restart, status) by directly managing process IDs, typically tracked in a PID file under /var/run/ or /run/. Understanding this legacy mechanism helps when you’re troubleshooting an older embedded system, a minimal container image, or diagnosing a custom-written init script that doesn’t behave quite like a well-formed systemd unit would.
Writing Scripts That Work Across Init Systems
If I’m writing a script meant to work reliably regardless of what’s managing services on the target system, I check for systemd’s presence explicitly rather than assuming:
#!/bin/bash
if pidof systemd >/dev/null 2>&1; then
systemctl restart nginx
else
service nginx restart
fi
In practice, for anything running on modern distributions (which is essentially everything you’ll deploy to today), I just use systemctl directly in scripts and reserve service for interactive terminal use, since the detection logic above is really only relevant for genuinely legacy or unusual environments.
Common Use Cases
- Quick interactive service checks during troubleshooting, where the shorter syntax of
service <name> statusbeats typing outsystemctl status <name>.service. - Working across mixed-generation infrastructure, where some older boxes still run SysVinit and you want one command that behaves consistently regardless.
- Onboarding people transitioning from older Linux experience, where
servicesyntax feels more immediately familiar than systemd’s unit-file-centric mental model. - Container images built without a full init system, where minimal shims sometimes provide just enough of
service‘s interface to manage a single foreground process.
Troubleshooting
“Unrecognized service” — the service name doesn’t match any known init script or systemd unit; check the exact name with systemctl list-units --type=service or ls /etc/init.d/.
Service reports “active” via service status but the application isn’t actually responding — the process manager considers the service running (the main process is alive) but the application itself might be stuck, deadlocked, or failing health checks internally; check application-level logs specifically, not just the service manager’s view of the process state.
journalctl -u nginx -n 50 --no-pager
Restart doesn’t seem to apply new configuration — confirm you actually edited the config file the running instance is reading (check for multiple config files or an included-but-overridden setting), and consider whether reload vs restart behaves differently for that particular service — some services cache configuration in ways that only a full restart clears.
service --status-all shows very few services on a systemd system — this is expected; the classic status-all output only reflects SysVinit-style init scripts, and many services on modern systemd systems exist purely as native .service unit files without any legacy init script at all, so they won’t appear in this particular listing even though they’re running fine. Use systemctl list-units --type=service for the complete modern picture.
Performance and Operational Considerations
service itself adds negligible overhead — it’s a lightweight detection-and-forwarding shell script. Any performance consideration really belongs to the service being managed and, more relevantly, to how gracefully that service handles reload versus full restart. I favor reload wherever a service supports it specifically to avoid connection drops for anything user-facing, reserving full restart for situations where the service genuinely needs to reinitialize from a clean process state (major version upgrades, memory leak mitigation, or configuration changes that a reload doesn’t pick up).
Security Implications
Service management commands require root privileges for anything beyond checking status, which is appropriate given the level of control involved — starting or stopping arbitrary system services is inherently a privileged operation. I’m always careful with sudo access delegation around service/systemctl specifically, since sudo rules that grant broad service management access can sometimes be leveraged for privilege escalation if a service can be configured or restarted in a way that executes attacker-controlled code as root — a classic pattern in sudo misconfiguration audits.
Checking Whether a Service Is Enabled at Boot vs Currently Running
A distinction I see confuse people constantly: a service can be running right now but not set to start automatically on the next boot, or vice versa — enabled for boot but not currently running (perhaps because it crashed, or was manually stopped since the last reboot). service alone can’t show you both dimensions at once; you need systemctl for the enabled/disabled state specifically:
systemctl is-active nginx
systemctl is-enabled nginx
I run both of these together whenever I’m auditing a server’s service configuration, since “currently running” and “will survive a reboot” are genuinely separate questions with separate real-world consequences — I’ve seen more than one incident where a service was manually started to fix an immediate problem, but nobody enabled it for boot, and it silently failed to come back after a routine maintenance reboot weeks later.
Using service Inside Configuration Management and Deployment Scripts
Even though I generally prefer systemctl directly in scripts for its more complete feature set, I’ve inherited plenty of older Ansible playbooks, Chef recipes, and shell-based deployment scripts that still use service calls, and they continue to work correctly on modern systemd systems precisely because of the compatibility forwarding described above. When maintaining older automation like this, I don’t feel a strong need to rewrite every service call to systemctl purely for its own sake — if it’s working reliably and the script doesn’t need boot-time enable/disable logic, leaving it as service is a perfectly reasonable choice that reduces unnecessary churn in a working deployment pipeline.
# A typical older-style deployment script snippet I still encounter
sudo service myapp stop
sudo cp new-build/myapp /opt/myapp/bin/
sudo service myapp start
sudo service myapp status
Checking Logs Alongside Service Status
service <name> status on a systemd-backed system typically shows a handful of recent log lines as part of its output, but for serious troubleshooting I go straight to journalctl for the full picture, since systemd itself is the one actually collecting and storing structured log output for the service:
journalctl -u nginx --since "1 hour ago"
journalctl -u nginx -f # follow live, like tail -f
journalctl -u nginx -p err # only error-priority and above
I treat service <name> status as the quick “is it up right now” check, and journalctl -u <name> as the actual investigative tool once something needs real troubleshooting.
Compatibility Across Distributions
service is available and functions as described across essentially all major Linux distributions today — Debian, Ubuntu, RHEL, CentOS, Fedora, and their many derivatives — specifically because all of them have adopted systemd and ship a service compatibility wrapper for exactly this reason. The underlying mechanism it forwards to (systemctl vs raw init scripts) differs by how the specific system is configured, but the command’s interface and behavior from a user’s perspective stays consistent.
Summary
service survives in the systemd era as a genuinely convenient compatibility layer — shorter to type, familiar to anyone with SysVinit-era experience, and functionally equivalent to the corresponding systemctl command for the everyday operations of starting, stopping, restarting, and checking status. Its real limitation is that it can’t manage boot-time autostart behavior at all, which remains exclusively systemctl‘s (or legacy update-rc.d/chkconfig‘s) territory. Once you understand that service is really just a friendly forwarding layer over whatever init system is actually in charge, its behavior stops being mysterious and becomes just another predictable tool in the admin toolkit.
References
man 8 serviceman 1 systemctl- freedesktop.org systemd documentation (freedesktop.org/wiki/Software/systemd/)
- Debian Wiki: SysVinit (wiki.debian.org/SysVinit)
- Red Hat documentation on systemd service management
