Start, stop, status and logs under control
Anyone who steers systemd services by trial and error wastes valuable time during outages in production. systemctl starts, stops and monitors services reliably, reads status output correctly, and recognizes states like failed or activating instantly and without guesswork. journalctl then delivers the matching, filtered logs for fast troubleshooting in production Linux environments and Magento deployments.
Table of Contents
- 1. Why systemd service management belongs in every admin's toolkit
- 2. Core systemctl commands: start, stop, restart
- 3. Reading service status correctly: Active, Loaded, Main PID
- 4. enable, disable and the role of symlinks
- 5. Analyzing logs with journalctl -u
- 6. Understanding service states: failed, activating, dead
- 7. Dependencies, timeouts and restart policies
- 8. Writing custom unit files for cron jobs and queues
- 9. systemctl versus SysVinit at a glance
- 10. Summary
- 11. FAQ
1. Why systemd service management belongs in every admin's toolkit
systemd has been the init process and service manager of nearly every mainstream Linux distribution for years now: Ubuntu, Debian, RHEL, CentOS, Fedora, SUSE. Anyone administering a server or running applications like PHP-FPM, Nginx, MySQL, Varnish, or a custom Magento queue consumer cannot avoid systemctl. Unlike the old SysVinit system with its shell scripts under /etc/init.d/, systemd offers a unified, declarative interface for every service, regardless of whether it should start automatically at boot, depend on other services, or restart itself automatically after a crash.
The practical benefit shows up most clearly during an incident: a storefront stops responding, a consumer stops processing messages, a cron job doesn't run. In all of these situations, the first step is almost always the same: check the affected service with systemctl status, review the last log lines, and correctly classify the state. Anyone who has this workflow down saves valuable minutes during an incident, instead of manually searching process lists or blindly tailing log files.
2. Core systemctl commands: start, stop, restart
The four core commands for daily operations are systemctl start, systemctl stop, systemctl restart and systemctl reload. start starts a service that is currently not running, stop shuts it down in a controlled way using the signal defined in the unit file, usually SIGTERM followed by SIGKILL once a timeout expires. restart is functionally a stop followed by a start and therefore always involves a brief moment of downtime. reload, on the other hand, signals the running process to re-read its configuration without terminating the process itself, which avoids dropped connections for Nginx or PHP-FPM.
For automation, the exit code of every command matters: systemctl restart returns 0 on success and a non-zero value on failure, which can be checked directly in deploy scripts with set -e. It is also important to understand the difference between systemctl start service and systemctl start service.service: if no suffix is given, systemctl automatically appends .service, but for timers, sockets or mount units the suffix must be given explicitly, otherwise the wrong unit gets addressed by accident.
# Start, stop and restart a single service
sudo systemctl start php8.3-fpm
sudo systemctl stop php8.3-fpm
sudo systemctl restart php8.3-fpm
# Reload config without downtime (only if the service supports it)
sudo systemctl reload nginx
# Combination of reload and restart as a safe fallback
sudo systemctl reload-or-restart nginx
# Check the exit code, e.g. inside a deploy script
if ! sudo systemctl restart php8.3-fpm; then
echo "[ERROR] php8.3-fpm restart failed" >&2
exit 1
fi
# Manage several services in a single call
sudo systemctl restart nginx php8.3-fpm supervisor
3. Reading service status correctly: Active, Loaded, Main PID
systemctl status service.service delivers far more information than a simple "running" or "not running" state. The Loaded: line shows whether the unit file was found and parsed, plus the current enabled status. The Active: line is the most important one: it shows the combined state of a high level status (active, inactive, failed) and a low level detail in parentheses (running, exited, dead), together with the time elapsed since the last state change. A service can be active (running) when it is meant to stay up permanently, or active (exited) when it is a oneshot service that runs once and then exits, without that being an error at all.
The Main PID: line shows the process ID of the main process together with the actual running command, which helps locate the service in ps or htop. Below that, systemd lists the current cgroup hierarchy with all child processes, which is especially useful for services with several worker processes, such as PHP-FPM or Supervisor. At the end of the output, the last log lines from the journal appear automatically, so an initial diagnosis often does not even require switching to journalctl.
$ systemctl status nginx.service
● nginx.service - A high performance web server and reverse proxy server
Loaded: loaded (/lib/systemd/system/nginx.service; enabled; vendor preset: enabled)
Active: active (running) since Sun 2026-07-12 08:14:03 UTC; 2h 11min ago
Docs: man:nginx(8)
Process: 1042 ExecStartPre=/usr/sbin/nginx -t -q -g daemon on; master_process on; (code=exited, status=0/SUCCESS)
Main PID: 1055 (nginx)
Tasks: 5 (limit: 4915)
Memory: 12.4M
CPU: 891ms
CGroup: /system.slice/nginx.service
├─1055 nginx: master process /usr/sbin/nginx -g daemon on; master_process on;
├─1056 nginx: worker process
└─1057 nginx: worker process
Jul 12 08:14:03 web01 systemd[1]: Starting A high performance web server...
Jul 12 08:14:03 web01 systemd[1]: Started A high performance web server and reverse proxy server.
4. enable, disable and the role of symlinks
A service can be running without starting automatically on the next boot, and conversely, it can be scheduled for boot without currently being active. systemctl start and systemctl enable are therefore independent switches for two separate questions: is the service running right now, and should it start automatically at system boot. systemctl enable technically creates a symlink from the unit file into the appropriate .wants directory of the configured target, usually /etc/systemd/system/multi-user.target.wants/. systemctl disable removes exactly that symlink again, without affecting the currently running process.
For deploy automation, systemctl enable --now redis-server is the convenient combo command that sets the symlink and starts the service in the same step, while systemctl disable redis-server removes the symlink again without stopping the running process. Whether a service is currently enabled for autostart is shown by systemctl is-enabled redis-server, and the running state comes from systemctl is-active redis-server. After any change to a unit file itself, for example adjusting ExecStart or Restart, systemctl daemon-reload must be run so systemd re-reads the file. If this step is forgotten, systemd keeps working with the old, cached definition held in memory, which leads to confusing situations in which a configuration change appears to have no effect at all. An overview of every service enabled for autostart comes from systemctl list-unit-files --state=enabled.
5. Analyzing logs with journalctl -u
journalctl is the central tool for reading logs that systemd stores in the binary, structured systemd journal. The most important filter for everyday work is -u, which restricts the output to a single unit: journalctl -u nginx.service shows only log entries from that service, regardless of whether they were written via stdout, stderr, or the native systemd logging API. This replaces the tedious grep-filtering across shared log files where several services mix their output together.
The -f flag follows the log live, similar to tail -f, and is the standard way to watch output during a deployment or restart. With --since and --until the time range can be narrowed precisely, and relative expressions like "1 hour ago" work just as well as absolute timestamps. For structured post-processing, -o json emits every log line as its own JSON object with all metadata, such as PID, priority and boot ID, which feeds nicely into log aggregators like Fluentd or Logstash. -p err additionally filters by priority and shows only errors and more critical messages.
# Follow a service's log live
journalctl -u php8.3-fpm.service -f
# Only error priority and higher, from the last hour
journalctl -u php8.3-fpm.service -p err --since "1 hour ago"
# Logs since the last boot, with precise local timestamps
journalctl -u nginx.service -b --output=short-precise
# Logs from several units, merged and sorted by time
journalctl -u nginx.service -u php8.3-fpm.service --since today
# Cap journal size to keep disk usage under control
sudo journalctl --vacuum-size=500M
sudo journalctl --vacuum-time=14d
6. Understanding service states: failed, activating, dead
The failed state means the service was started but exited with an error, or an ExecStart command itself failed. A failed state persists until it is either manually reset with systemctl reset-failed or the service is successfully restarted. The activating state is, for most services, a brief transitional state during startup, but for misconfigured services with slow health checks it can remain for minutes, especially for services of type notify, which wait for a readiness signal from the process itself.
dead simply describes a stopped service without any error, for example after a planned systemctl stop. The difference between inactive and failed is crucial for monitoring systems: inactive is usually an intentional state, failed is always an alarm signal. systemctl --failed lists every unit in a failure state across the whole server and is therefore the fastest first command to run during a general outage report, before checking individual services in detail. A failed state can be cleared specifically with systemctl reset-failed myapp-worker.service, and inside a script the current state can be queried and evaluated directly via systemctl is-active myapp-worker.service.
7. Dependencies, timeouts and restart policies
systemd models dependencies between services explicitly through directives like Requires=, Wants= and After=. Requires= enforces that the dependent unit must also start, otherwise the start fails; if the dependency later fails, the dependent unit is stopped along with it. Wants= is the weaker, recommended variant for most use cases: it attempts to start the other unit as well, but does not fail if that does not succeed. After= and Before= control only the startup order, without creating a dependency in the "must be running" sense on their own, which is why Wants= and After= are usually combined together in practice.
For fault tolerance, the Restart= directive is decisive: Restart=on-failure only restarts the service automatically after a failure state, while Restart=always does so even after a regular exit code of 0. RestartSec= defines the wait time between restart attempts, while StartLimitBurst= and StartLimitIntervalSec= prevent a permanently crashing service from driving systemd into an infinite restart loop that puts the server under load.
8. Writing custom unit files for cron jobs and queues
For long-lived background processes like a Magento message queue consumer, a dedicated unit file is more robust than a cron job using nohup or a manually started screen session. Custom unit files belong in /etc/systemd/system/, not in /lib/systemd/system/, which stays reserved for the package manager. The [Service] block with Type=simple defines the standard case of a process running in the foreground, User= and Group= ensure the consumer doesn't accidentally run as root, and WorkingDirectory= sets the working directory correctly before the command is executed.
After creating a new unit file, the order is always the same: daemon-reload, then enable --now. For consumers that might crash occasionally, for example due to an out-of-memory kill by the kernel, Restart=always combined with RestartSec=5 provides automatic recovery without requiring an extra supervisor tool like Supervisord.
# /etc/systemd/system/magento-consumer-inventory.service
[Unit]
Description=Magento Inventory Reservation Queue Consumer
After=network.target mysql.service rabbitmq-server.service
Wants=rabbitmq-server.service
[Service]
Type=simple
User=deploy
Group=deploy
WorkingDirectory=/var/www/magento
ExecStart=/usr/bin/php bin/magento queue:consumers:start inventory.reservation.updateSalabilityAfterOrderPlacement --max-messages=1000
Restart=always
RestartSec=5
StartLimitIntervalSec=60
StartLimitBurst=5
TimeoutStopSec=30
StandardOutput=journal
StandardError=journal
SyslogIdentifier=magento-consumer-inventory
[Install]
WantedBy=multi-user.target
For automation and CI/CD it helps to know that a unit's state can also be read in a machine-readable way: systemctl show magento-consumer-inventory.service --output=json -p ExecMainStatus -p Result -p ActiveState -p SubState -p MainPID returns exactly those fields as a JSON object, which plugs directly into monitoring scripts or deploy pipelines without having to parse the textual status output.
# Ansible task: deploy a systemd unit and ensure its target state
- name: Deploy magento consumer unit file
ansible.builtin.template:
src: magento-consumer-inventory.service.j2
dest: /etc/systemd/system/magento-consumer-inventory.service
mode: "0644"
notify: reload systemd
- name: Ensure consumer service is enabled and running
ansible.builtin.systemd:
name: magento-consumer-inventory.service
enabled: true
state: started
daemon_reload: true
handlers:
- name: reload systemd
ansible.builtin.systemd:
daemon_reload: true
Mironsoft
Server administration, deployment automation and systemd setups
Reliable systemd services for your stack?
We set up unit files for queue consumers, cron jobs and background processes, configure restart policies and dependencies correctly, and put monitoring in place that reports failed states immediately.
Unit setup
Robust unit files for consumers, workers and cron jobs
Monitoring
Alerting on failed states via journalctl and external tools
Deploy automation
Ansible roles for systemd deployments in CI/CD pipelines
9. systemctl versus SysVinit at a glance
Anyone moving from classic init.d scripts to systemd usually looks for the direct equivalent of a familiar command. The table below maps the most important old patterns to their modern systemctl equivalents.
| Task | Old way (SysVinit) | systemd equivalent | Benefit |
|---|---|---|---|
| Start a service | service apache2 start |
systemctl start apache2 |
Uniform interface for every service |
| Enable autostart | update-rc.d apache2 defaults |
systemctl enable apache2 |
Symlink-based, instantly traceable |
| Inspect logs | tail -f /var/log/apache2/error.log |
journalctl -u apache2 -f |
Structured, with metadata and filters |
| Check status | ps aux | grep apache2 |
systemctl status apache2 |
Shows PID, memory, state and logs |
| Automatic restart | Custom watchdog script via cron | Restart=on-failure in the unit file |
No extra tooling needed |
The switch pays off mainly because systemd delivers a consistent view of every service, regardless of whether it is a package-installed web server or a hand-written unit for a Magento consumer. Anyone who masters systemctl and journalctl no longer needs additional tooling for the vast majority of diagnostic and operational tasks.
10. Summary
Managing systemd services boils down to a handful of clearly defined commands: systemctl start/stop/restart for the running state, systemctl enable/disable for autostart, and systemctl status as the first point of contact for every incident. The status output already provides most of the information needed for an initial diagnosis through Active:, Loaded: and Main PID:, without requiring extra tools. journalctl -u adds filtered, structured logs that can be followed live, narrowed by time, and filtered by priority.
Anyone who correctly interprets the meaning of the states failed, activating and dead, and writes custom unit files with clean restart policies and dependencies, replaces fragile cron or nohup constructs with production-grade processes supervised by the kernel. systemctl --failed as a server-wide overview and daemon-reload after every unit change are among the commands that no admin's daily routine can do without.
Managing systemd Services, the essentials at a glance
Core commands
systemctl start/stop/restart for the running state, enable --now for autostart plus an immediate start in a single step.
Reading status
Active:, Loaded: and Main PID: deliver the central diagnosis directly in the status output.
Logs with journalctl
journalctl -u service -f to follow live, -p err and --since for targeted filtering.
States & policies
systemctl --failed as a server-wide overview, Restart=on-failure for automatic recovery.