Mastering Service Management: How to Start a Service in Linux Using systemd and Legacy Tools
Web service down at 2 a.m.? Experienced engineers know: properly starting and monitoring Linux services is key to minimizing downtime. Whether rolling out a stateful application or debugging an errant daemon on RHEL 8 or Ubuntu 22.04, the method you use makes all the difference.
Service Control: Why It Still Matters
In Linux, a “service” is a managed daemon—typically requiring predictable boot, lifecycle control, and reliable restarts on failure. Systemd’s rise reshaped best practices, but legacy methods persist in production—especially in environments with older distros, chrooted workloads, or vendor appliances. The method you choose impacts both consistency and troubleshooting.
Critical scenarios:
- Emergency restarts after OOM kills (
systemctl restart nginx
) - Deploying custom code with zero downtime
- Diagnostic checks (systemd units stuck in failed state; see below)
Modern Standard: systemd (2014+)
Linux distributions adopted systemd at different rates. Fedora went first, with RHEL 7, Debian 8 (“jessie”), and Ubuntu 15.04+ following. systemd displaced messy runlevel scripts, introducing parallelization and rich dependency graphs.
Features:
- Parallel startup (speeds up boot, but can create race conditions)
- Precise status reporting (
systemctl status
) - On-demand activation (socket/unit triggers)
- Rich logging (
journalctl -u sshd
) - Consistent interface regardless of distribution
Command patterns:
sudo systemctl start <unit>
sudo systemctl stop <unit>
sudo systemctl restart <unit>
sudo systemctl status <unit>
Practical example: Apache on Ubuntu 22.04
sudo systemctl start apache2
sudo systemctl enable apache2
sudo systemctl status apache2
Gotcha: If systemctl start
succeeds but the service fails immediately, run:
journalctl -xeu apache2
Look for hints: “Permission denied,” “Address already in use,” or missing config files.
Enabling at boot:
sudo systemctl enable <unit>
This symlinks unit files under /etc/systemd/system/multi-user.target.wants/
.
What about Sockets?
Some services (e.g., sshd.socket
) can be started on-demand by sockets. Check with:
systemctl list-sockets
Legacy Approach: SysV Init Scripts
Still present in RHEL 6.x, SLES 11, and some container base images. Service scripts reside in /etc/init.d/
or /etc/rc.d/init.d/
.
Pattern:
sudo /etc/init.d/<service> start
or via compatibility wrapper:
sudo service <service> start
Example:
sudo /etc/init.d/nagios start
Note: On some systemd distros, /etc/init.d/*
scripts are emulated via systemd “shim” units. You might see non-obvious failures or degraded logs—don’t blindly trust success messages.
Choosing the Right Approach
Environment | Preferred Command |
---|---|
Fedora 21+, RHEL 7+, Ubuntu 15.04+, Debian 8+ | systemctl |
RHEL/CentOS 6, Debian 7, Ubuntu 14.04 and earlier | service or /etc/init.d/ |
Minimal containers, vendor appliances | Check for available tools; systemd may not be present |
Hybrid systems (e.g., some Docker containers, WSL instances) may respond to service
but not systemctl
, due to lack of underlying init infrastructure. Always check ps 1
to see what init system is running.
Creating a Custom systemd Unit
Default units are rarely enough for custom applications or nonstandard requirements. A minimal example:
/etc/systemd/system/myapi.service
[Unit]
Description=My API Worker
After=network.target
[Service]
Type=simple
ExecStart=/usr/local/bin/myapi --config=/etc/myapi/config.yaml
User=myappuser
Restart=on-failure
RestartSec=2
[Install]
WantedBy=multi-user.target
Critical: After creating or editing a unit, always reload systemd's daemon:
sudo systemctl daemon-reload
Enable and start your service:
sudo systemctl enable myapi
sudo systemctl start myapi
Non-obvious tip: For troubleshooting, override a systemd unit without editing the vendor file:
sudo systemctl edit myapi
This places drop-in configuration in /etc/systemd/system/myapi.service.d/override.conf
.
Summary Table
Task | systemd (systemctl ) | SysV/Legacy |
---|---|---|
Start | sudo systemctl start foo | sudo service foo start or /etc/init.d/foo start |
Stop | sudo systemctl stop foo | sudo service foo stop |
Status | sudo systemctl status foo | sudo service foo status |
Enable at boot | sudo systemctl enable foo | Manually symlink in /etc/rc*.d/ or edit /etc/init/ configs |
View logs | journalctl -u foo | Inspect /var/log/ manually |
Failure Modes—And What to Look For
- systemctl returns exit code 0, but nothing happens: Check if you’re inside a container with no init system.
- service exits but logs are unclear: Legacy services often swallow log output; always check
/var/log/syslog
,/var/log/messages
, or custom log files. - Systemd unit stuck in “failed” state: Use
systemctl reset-failed foo
to clear, then restart and check detailed logs.
In Practice
Seasoned engineers routinely mix these methods, especially when managing mixed-generation fleets or highly customized environments. Not every application ships a clean systemd unit; don’t be afraid to write—or adapt—unit files. But know that differences in PID handling, user context, and environment propagation exist between legacy and modern methods—side effects matter.
If you need advanced troubleshooting or want a deep-dive into templated unit files for scaling dynamic workloads, call it out.